From 2d0bd43f697630ddf5353bd031f700502c25f936 Mon Sep 17 00:00:00 2001 From: adrigzr Date: Thu, 23 Mar 2023 17:46:41 +0100 Subject: [PATCH] test: raise coverage --- package.json | 14 +- .../packet-connection.aggregate-root.test.ts | 316 +++++ .../packet-connection.aggregate-root.ts | 45 +- .../locate-device.command-handler.test.ts | 51 + .../locate-device.command-handler.ts | 21 + .../locate-device.event-handler.ts | 31 - .../connection-device-updater.service.test.ts | 64 + .../src/connection-device-updater.service.ts | 29 + ...nected-event-handler.event-handler.test.ts | 45 + ...s-connected-event-handler.event-handler.ts | 17 +- ...locked-event-handler.event-handler.test.ts | 70 + ...e-is-locked-event-handler.event-handler.ts | 17 +- ...ction-device-changed.event-handler.test.ts | 100 ++ ...onnection-device-changed.event-handler.ts} | 9 +- .../src/factories/connection.factory.test.ts | 32 + packages/adapter-tcp/src/index.ts | 2 +- .../src/mappers/clean-mode.mapper.test.ts | 29 + .../src/mappers/device-battery.mapper.test.ts | 43 + .../src/mappers/device-error.mapper.test.ts | 31 + .../src/mappers/device-error.mapper.ts | 2 +- .../mappers/device-fan-speed.mapper.test.ts | 29 + .../src/mappers/device-mode.mapper.test.ts | 52 + .../src/mappers/device-mode.mapper.ts | 2 +- .../src/mappers/device-order.mapper.test.ts | 179 +++ .../src/mappers/device-state.mapper.test.ts | 76 ++ .../src/mappers/device-state.mapper.ts | 2 +- .../mappers/device-water-level.mapper.test.ts | 29 + .../src/mappers/voice-setting.mapper.test.ts | 39 + ...oice.mapper.ts => voice-setting.mapper.ts} | 2 +- .../src/mappers/week-day-list.mapper.test.ts | 10 +- .../packet-connection-finder.service.test.ts | 53 + .../src/packet-connection-finder.service.ts | 20 + .../client-heartbeat.event-handler.test.ts | 26 + .../client-login.event-handler.test.ts | 53 + ...evice-battery-update.event-handler.test.ts | 49 + .../device-battery-update.event-handler.ts | 5 +- .../device-settings-update.event-handler.ts | 4 +- .../packet-event-publisher.service.test.ts | 51 + .../src/packet-event-publisher.service.ts | 31 + .../packet-server.connection-handler.test.ts | 152 +++ .../src/packet-server.connection-handler.ts | 95 +- .../adapter-tcp/src/packet.message.test.ts | 119 ++ packages/adapter-tcp/src/packet.message.ts | 19 + packages/adapter-tcp/src/tcp.server.test.ts | 7 +- packages/adapter-tcp/src/tcp.server.ts | 26 +- .../find-device.query-handler.test.ts | 48 + .../src/queries/find-device-query.test.ts | 60 + packages/eslint-config/package.json | 8 +- packages/schemas-tcp/src/index.proto | 2 +- .../transport-tcp/src/packet.socket.test.ts | 24 +- packages/transport-tcp/src/packet.socket.ts | 3 +- yarn.lock | 1202 +++++++++-------- 52 files changed, 2724 insertions(+), 721 deletions(-) create mode 100644 packages/adapter-tcp/src/aggregate-roots/packet-connection.aggregate-root.test.ts create mode 100644 packages/adapter-tcp/src/command-handlers/locate-device.command-handler.test.ts create mode 100644 packages/adapter-tcp/src/command-handlers/locate-device.command-handler.ts delete mode 100644 packages/adapter-tcp/src/command-handlers/locate-device.event-handler.ts create mode 100644 packages/adapter-tcp/src/connection-device-updater.service.test.ts create mode 100644 packages/adapter-tcp/src/connection-device-updater.service.ts create mode 100644 packages/adapter-tcp/src/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.test.ts create mode 100644 packages/adapter-tcp/src/domain-event-handlers/query-device-info-when-device-is-locked-event-handler.event-handler.test.ts create mode 100644 packages/adapter-tcp/src/domain-event-handlers/set-device-connected-when-connection-device-changed.event-handler.test.ts rename packages/adapter-tcp/src/domain-event-handlers/{set-device-connected-when-connection-device-changed.domain-event.ts => set-device-connected-when-connection-device-changed.event-handler.ts} (67%) create mode 100644 packages/adapter-tcp/src/factories/connection.factory.test.ts create mode 100644 packages/adapter-tcp/src/mappers/clean-mode.mapper.test.ts create mode 100644 packages/adapter-tcp/src/mappers/device-battery.mapper.test.ts create mode 100644 packages/adapter-tcp/src/mappers/device-error.mapper.test.ts create mode 100644 packages/adapter-tcp/src/mappers/device-fan-speed.mapper.test.ts create mode 100644 packages/adapter-tcp/src/mappers/device-mode.mapper.test.ts create mode 100644 packages/adapter-tcp/src/mappers/device-order.mapper.test.ts create mode 100644 packages/adapter-tcp/src/mappers/device-state.mapper.test.ts create mode 100644 packages/adapter-tcp/src/mappers/device-water-level.mapper.test.ts create mode 100644 packages/adapter-tcp/src/mappers/voice-setting.mapper.test.ts rename packages/adapter-tcp/src/mappers/{device-voice.mapper.ts => voice-setting.mapper.ts} (91%) create mode 100644 packages/adapter-tcp/src/packet-connection-finder.service.test.ts create mode 100644 packages/adapter-tcp/src/packet-connection-finder.service.ts create mode 100644 packages/adapter-tcp/src/packet-event-handlers/client-heartbeat.event-handler.test.ts create mode 100644 packages/adapter-tcp/src/packet-event-handlers/client-login.event-handler.test.ts create mode 100644 packages/adapter-tcp/src/packet-event-handlers/device-battery-update.event-handler.test.ts create mode 100644 packages/adapter-tcp/src/packet-event-publisher.service.test.ts create mode 100644 packages/adapter-tcp/src/packet-event-publisher.service.ts create mode 100644 packages/adapter-tcp/src/packet-server.connection-handler.test.ts create mode 100644 packages/adapter-tcp/src/packet.message.test.ts create mode 100644 packages/core/src/query-handlers/find-device.query-handler.test.ts create mode 100644 packages/domain/src/queries/find-device-query.test.ts diff --git a/package.json b/package.json index 0b45e952..fe1e457e 100755 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ } }, "devDependencies": { - "@commitlint/cli": "^17.4.4", + "@commitlint/cli": "^17.5.0", "@commitlint/config-conventional": "^17.4.4", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@johanblumenberg/ts-mockito": "^1.0.35", @@ -38,23 +38,23 @@ "@types/debug": "^4.1.7", "@types/mocha": "^10.0.1", "@types/mock-fs": "^4.13.1", - "@types/node": "^18.14.2", + "@types/node": "^18.15.5", "chai": "^4.3.7", "chai-as-promised": "^7.1.1", "commitizen": "^4.3.0", "cz-conventional-changelog": "^3.3.0", "husky": "^8.0.3", "json": "^11.0.0", - "lerna": "^6.5.1", - "lint-staged": ">=13.1.2", + "lerna": "^6.6.0", + "lint-staged": ">=13.2.0", "mocha": "^10.2.0", - "npm-check-updates": "^16.7.9", + "npm-check-updates": "^16.8.0", "npm-run-all": "^4.1.5", "nyc": "^15.1.0", - "prettier": "2.8.4", + "prettier": "2.8.6", "ts-node": "^10.9.1", "tsconfig-paths": "^4.1.2", - "typedoc": "^0.23.25", + "typedoc": "^0.23.28", "typedoc-plugin-resolve-crossmodule-references": "^0.3.3", "typescript": "^4.9.5", "yarn-deduplicate": "^6.0.1" diff --git a/packages/adapter-tcp/src/aggregate-roots/packet-connection.aggregate-root.test.ts b/packages/adapter-tcp/src/aggregate-roots/packet-connection.aggregate-root.test.ts new file mode 100644 index 00000000..12beb90d --- /dev/null +++ b/packages/adapter-tcp/src/aggregate-roots/packet-connection.aggregate-root.test.ts @@ -0,0 +1,316 @@ +import { Socket, Server } from 'net'; +import { Connection, Device } from '@agnoc/domain'; +import { givenSomeDeviceProps } from '@agnoc/domain/test-support'; +import { ArgumentInvalidException, ArgumentNotProvidedException, DomainException, ID } from '@agnoc/toolkit'; +import { Packet, PacketSocket } from '@agnoc/transport-tcp'; +import { givenSomePacketProps } from '@agnoc/transport-tcp/test-support'; +import { anything, deepEqual, defer, imock, instance, spy, verify, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { PacketConnection } from './packet-connection.aggregate-root'; +import type { PacketEventBus } from '../packet.event-bus'; +import type { PacketMessage } from '../packet.message'; +import type { PacketFactory, PacketMapper } from '@agnoc/transport-tcp'; +import type { AddressInfo } from 'net'; + +describe('PacketConnection', function () { + let packetFactory: PacketFactory; + let eventBus: PacketEventBus; + let packetMapper: PacketMapper; + let packetSocket: PacketSocket; + let packetSocketSpy: PacketSocket; + let packetMessage: PacketMessage; + let socket: Socket; + let server: Server; + + beforeEach(function () { + server = new Server(); + socket = new Socket(); + packetFactory = imock(); + eventBus = imock(); + packetMapper = imock(); + packetMessage = imock(); + packetSocket = new PacketSocket(instance(packetMapper), socket); + packetSocketSpy = spy(packetSocket); + }); + + it('should be created', function () { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + + expect(connection).to.be.instanceOf(Connection); + expect(connection.id).to.be.equal(props.id); + expect(connection.socket).to.be.equal(props.socket); + expect(connection.connectionType).to.be.equal('PACKET'); + expect(PacketConnection.isPacketConnection(connection)).to.be.true; + }); + + it("should throw an error when 'socket' is not provided", function () { + expect( + // @ts-expect-error - invalid property + () => new PacketConnection(instance(packetFactory), instance(eventBus), { id: ID.generate(), socket: undefined }), + ).to.throw(ArgumentNotProvidedException, `Property 'socket' for PacketConnection not provided`); + }); + + it("should throw an error when 'socket' is not a PacketSocket", function () { + expect( + // @ts-expect-error - invalid property + () => new PacketConnection(instance(packetFactory), instance(eventBus), { id: ID.generate(), socket: 'foo' }), + ).to.throw( + ArgumentInvalidException, + `Value 'foo' for property 'socket' of PacketConnection is not an instance of PacketSocket`, + ); + }); + + describe('#send()', function () { + it('should do nothing', async function () { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + const packet = new Packet(givenSomePacketProps()); + const data = { result: 0, body: { deviceTime: 1 } }; + + when(packetFactory.create(anything(), anything(), anything())).thenReturn(packet); + + await expect(connection.send('DEVICE_GETTIME_RSP', data)).to.be.rejectedWith( + DomainException, + 'Unable to send packet through a closed connection', + ); + + verify(packetFactory.create(anything(), anything(), anything())).never(); + verify(packetSocketSpy.write(anything())).never(); + }); + }); + + describe('#respond()', function () { + it('should do nothing', async function () { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + const packet = new Packet(givenSomePacketProps()); + const anotherPacket = new Packet(givenSomePacketProps()); + const data = { result: 0, body: { deviceTime: 1 } }; + + when(packetFactory.create(anything(), anything(), anything())).thenReturn(anotherPacket); + + await expect(connection.respond('DEVICE_GETTIME_RSP', data, packet)).to.be.rejectedWith( + DomainException, + 'Unable to send packet through a closed connection', + ); + + verify(packetFactory.create(anything(), anything(), anything())).never(); + verify(packetSocketSpy.write(anything())).never(); + }); + }); + + describe('#sendAndWait()', function () { + it('should do nothing', async function () { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + const packet = new Packet(givenSomePacketProps()); + const data = { result: 0, body: { deviceTime: 1 } }; + + when(packetFactory.create(anything(), anything(), anything())).thenReturn(packet); + + await expect(connection.sendAndWait('DEVICE_GETTIME_RSP', data)).to.be.rejectedWith( + DomainException, + 'Unable to send packet through a closed connection', + ); + + verify(packetFactory.create(anything(), anything(), anything())).never(); + verify(packetSocketSpy.write(anything())).never(); + }); + }); + + describe('#respondAndWait()', function () { + it('should do nothing', async function () { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + const packet = new Packet(givenSomePacketProps()); + const data = { result: 0, body: { deviceTime: 1 } }; + + when(packetFactory.create(anything(), anything(), anything())).thenReturn(packet); + + await expect(connection.respondAndWait('DEVICE_GETTIME_RSP', data, packet)).to.be.rejectedWith( + DomainException, + 'Unable to send packet through a closed connection', + ); + + verify(packetFactory.create(anything(), anything(), anything())).never(); + verify(packetSocketSpy.write(anything())).never(); + }); + }); + + describe('#close()', function () { + it('should do nothing', async function () { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + + await connection.close(); + + verify(packetSocketSpy.end()).never(); + }); + }); + + describe('with socket connected', function () { + beforeEach(function (done) { + server.listen(0, () => { + socket.connect((server.address() as AddressInfo).port, done); + }); + }); + + afterEach(function (done) { + if (socket.readyState === 'open') { + socket.end(); + } + + if (server.listening) { + server.close(done); + } else { + done(); + } + }); + + describe('#send()', function () { + it('should send a packet', async function () { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + const packet = new Packet(givenSomePacketProps()); + const data = { result: 0, body: { deviceTime: 1 } }; + + when(packetFactory.create(anything(), anything(), anything())).thenReturn(packet); + when(packetMapper.fromDomain(anything())).thenReturn(Buffer.alloc(0)); + + await connection.send('DEVICE_GETTIME_RSP', data); + + verify( + packetFactory.create('DEVICE_GETTIME_RSP', data, deepEqual({ deviceId: new ID(0), userId: new ID(0) })), + ).once(); + verify(packetSocketSpy.write(packet)).once(); + }); + + it('should send a packet with a device attached', async function () { + const device = new Device(givenSomeDeviceProps()); + const props = { id: ID.generate(), socket: packetSocket, device }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + const packet = new Packet(givenSomePacketProps()); + const data = { result: 0, body: { deviceTime: 1 } }; + + when(packetFactory.create(anything(), anything(), anything())).thenReturn(packet); + when(packetMapper.fromDomain(anything())).thenReturn(Buffer.alloc(0)); + + await connection.send('DEVICE_GETTIME_RSP', data); + + verify( + packetFactory.create('DEVICE_GETTIME_RSP', data, deepEqual({ deviceId: device.id, userId: device.userId })), + ).once(); + verify(packetSocketSpy.write(packet)).once(); + }); + }); + + describe('#respond()', function () { + it('should respond with a packet', async function () { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + const packet = new Packet(givenSomePacketProps()); + const anotherPacket = new Packet(givenSomePacketProps()); + const data = { result: 0, body: { deviceTime: 1 } }; + + when(packetFactory.create(anything(), anything(), anything())).thenReturn(anotherPacket); + when(packetMapper.fromDomain(anything())).thenReturn(Buffer.alloc(0)); + + await connection.respond('DEVICE_GETTIME_RSP', data, packet); + + verify(packetFactory.create('DEVICE_GETTIME_RSP', data, packet)).once(); + verify(packetSocketSpy.write(anotherPacket)).once(); + }); + }); + + describe('#sendAndWait()', function () { + it('should send a packet and wait for the response', function (done) { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + const packet = new Packet(givenSomePacketProps()); + const data = { result: 0, body: { deviceTime: 1 } }; + const eventPromise = defer(); + + when(packetFactory.create(anything(), anything(), anything())).thenReturn(packet); + when(packetMapper.fromDomain(anything())).thenReturn(Buffer.alloc(0)); + when(eventBus.once(anything())).thenReturn(eventPromise); + + void connection.sendAndWait('DEVICE_GETTIME_RSP', data).then((ret) => { + expect(ret).to.be.equal(instance(packetMessage)); + + verify( + packetFactory.create('DEVICE_GETTIME_RSP', data, deepEqual({ deviceId: new ID(0), userId: new ID(0) })), + ).once(); + verify(packetSocketSpy.write(packet)).once(); + verify(eventBus.once(packet.sequence.toString())).once(); + done(); + }); + + void eventPromise.resolve(instance(packetMessage)); + }); + + it('should send a packet with a device attached and wait for the response', function (done) { + const device = new Device(givenSomeDeviceProps()); + const props = { id: ID.generate(), socket: packetSocket, device }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + const packet = new Packet(givenSomePacketProps()); + const data = { result: 0, body: { deviceTime: 1 } }; + const eventPromise = defer(); + + when(packetFactory.create(anything(), anything(), anything())).thenReturn(packet); + when(packetMapper.fromDomain(anything())).thenReturn(Buffer.alloc(0)); + when(eventBus.once(anything())).thenReturn(eventPromise); + + void connection.sendAndWait('DEVICE_GETTIME_RSP', data).then((ret) => { + expect(ret).to.be.equal(instance(packetMessage)); + + verify( + packetFactory.create('DEVICE_GETTIME_RSP', data, deepEqual({ deviceId: device.id, userId: device.userId })), + ).once(); + verify(packetSocketSpy.write(packet)).once(); + verify(eventBus.once(packet.sequence.toString())).once(); + done(); + }); + + void eventPromise.resolve(instance(packetMessage)); + }); + }); + + describe('#respondAndWait()', function () { + it('should respond to a packet and wait for the response', function (done) { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + const packet = new Packet(givenSomePacketProps()); + const anotherPacket = new Packet(givenSomePacketProps()); + const data = { result: 0, body: { deviceTime: 1 } }; + const eventPromise = defer(); + + when(packetFactory.create(anything(), anything(), anything())).thenReturn(anotherPacket); + when(packetMapper.fromDomain(anything())).thenReturn(Buffer.alloc(0)); + when(eventBus.once(anything())).thenReturn(eventPromise); + + void connection.respondAndWait('DEVICE_GETTIME_RSP', data, packet).then((ret) => { + expect(ret).to.be.equal(instance(packetMessage)); + + verify(packetFactory.create('DEVICE_GETTIME_RSP', data, packet)).once(); + verify(packetSocketSpy.write(anotherPacket)).once(); + verify(eventBus.once(packet.sequence.toString())).once(); + done(); + }); + + void eventPromise.resolve(instance(packetMessage)); + }); + }); + + describe('#close()', function () { + it('should close the socket', async function () { + const props = { id: ID.generate(), socket: packetSocket }; + const connection = new PacketConnection(instance(packetFactory), instance(eventBus), props); + + await connection.close(); + + verify(packetSocketSpy.end()).once(); + }); + }); + }); +}); diff --git a/packages/adapter-tcp/src/aggregate-roots/packet-connection.aggregate-root.ts b/packages/adapter-tcp/src/aggregate-roots/packet-connection.aggregate-root.ts index f474091f..2678a165 100644 --- a/packages/adapter-tcp/src/aggregate-roots/packet-connection.aggregate-root.ts +++ b/packages/adapter-tcp/src/aggregate-roots/packet-connection.aggregate-root.ts @@ -1,5 +1,5 @@ import { Connection } from '@agnoc/domain'; -import { ID } from '@agnoc/toolkit'; +import { DomainException, ID } from '@agnoc/toolkit'; import { PacketSocket } from '@agnoc/transport-tcp'; import type { PacketEventBus } from '../packet.event-bus'; import type { PacketMessage } from '../packet.message'; @@ -25,37 +25,48 @@ export class PacketConnection extends Connection { return this.props.socket; } - send(name: Name, object: PayloadDataFrom): Promise { - const packet = this.packetFactory.create(name, object, this.getPacketProps()); + async send(name: Name, data: PayloadDataFrom): Promise { + this.validateConnectedSocket(); - return this.write(packet); + const packet = this.packetFactory.create(name, data, this.getPacketProps()); + + return this.socket.write(packet); } - respond(name: Name, object: PayloadDataFrom, packet: Packet): Promise { - return this.write(this.packetFactory.create(name, object, packet)); + async respond(name: Name, data: PayloadDataFrom, packet: Packet): Promise { + this.validateConnectedSocket(); + + return this.socket.write(this.packetFactory.create(name, data, packet)); } - sendAndWait(name: Name, object: PayloadDataFrom): Promise { - const packet = this.packetFactory.create(name, object, this.getPacketProps()); + async sendAndWait(name: Name, data: PayloadDataFrom): Promise { + this.validateConnectedSocket(); + + const packet = this.packetFactory.create(name, data, this.getPacketProps()); return this.writeAndWait(packet); } - respondAndWait( + async respondAndWait( name: Name, - object: PayloadDataFrom, + data: PayloadDataFrom, packet: Packet, ): Promise { - return this.writeAndWait(this.packetFactory.create(name, object, packet)); + this.validateConnectedSocket(); + + return this.writeAndWait(this.packetFactory.create(name, data, packet)); } - close(): Promise { + async close(): Promise { + if (!this.socket.connected) { + return; + } + return this.socket.end(); } protected override validate(props: PacketConnectionProps): void { super.validate(props); - this.validateDefinedProp(props, 'socket'); this.validateInstanceProp(props, 'socket', PacketSocket); } @@ -67,16 +78,14 @@ export class PacketConnection extends Connection { private writeAndWait(packet: Packet): Promise { return new Promise((resolve, reject) => { this.eventBus.once(packet.sequence.toString()).then(resolve, reject); - this.write(packet).catch(reject); + this.socket.write(packet).catch(reject); }); } - private async write(packet: Packet) { + private validateConnectedSocket(): void { if (!this.socket.connected) { - return; + throw new DomainException('Unable to send packet through a closed connection'); } - - return this.socket.write(packet); } static isPacketConnection(connection: Connection): connection is PacketConnection { diff --git a/packages/adapter-tcp/src/command-handlers/locate-device.command-handler.test.ts b/packages/adapter-tcp/src/command-handlers/locate-device.command-handler.test.ts new file mode 100644 index 00000000..24b3e72a --- /dev/null +++ b/packages/adapter-tcp/src/command-handlers/locate-device.command-handler.test.ts @@ -0,0 +1,51 @@ +import { LocateDeviceCommand } from '@agnoc/domain'; +import { ID } from '@agnoc/toolkit'; +import { imock, instance, when, verify, anything, deepEqual } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { LocateDeviceCommandHandler } from './locate-device.command-handler'; +import type { PacketConnection } from '../aggregate-roots/packet-connection.aggregate-root'; +import type { PacketConnectionFinderService } from '../packet-connection-finder.service'; +import type { PacketMessage } from '../packet.message'; + +describe('LocateDeviceCommandHandler', function () { + let packetConnectionFinderService: PacketConnectionFinderService; + let commandHandler: LocateDeviceCommandHandler; + let packetConnection: PacketConnection; + let packetMessage: PacketMessage; + + beforeEach(function () { + packetConnectionFinderService = imock(); + commandHandler = new LocateDeviceCommandHandler(instance(packetConnectionFinderService)); + packetConnection = imock(); + packetMessage = imock(); + }); + + it('should define the name', function () { + expect(commandHandler.forName).to.be.equal('LocateDeviceCommand'); + }); + + describe('#handle()', function () { + it('should send locate device command', async function () { + const command = new LocateDeviceCommand({ deviceId: new ID(1) }); + + when(packetConnectionFinderService.findByDeviceId(anything())).thenResolve(instance(packetConnection)); + when(packetConnection.sendAndWait(anything(), anything())).thenResolve(instance(packetMessage)); + + await commandHandler.handle(command); + + verify(packetConnection.sendAndWait('DEVICE_SEEK_LOCATION_REQ', deepEqual({}))).once(); + verify(packetMessage.assertPayloadName('DEVICE_SEEK_LOCATION_RSP')).once(); + }); + + it('should do nothing when no connection is found', async function () { + const command = new LocateDeviceCommand({ deviceId: new ID(1) }); + + when(packetConnectionFinderService.findByDeviceId(anything())).thenResolve(undefined); + + await commandHandler.handle(command); + + verify(packetConnection.sendAndWait(anything(), anything())).never(); + verify(packetMessage.assertPayloadName(anything())).never(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/command-handlers/locate-device.command-handler.ts b/packages/adapter-tcp/src/command-handlers/locate-device.command-handler.ts new file mode 100644 index 00000000..945a489e --- /dev/null +++ b/packages/adapter-tcp/src/command-handlers/locate-device.command-handler.ts @@ -0,0 +1,21 @@ +import type { PacketConnectionFinderService } from '../packet-connection-finder.service'; +import type { PacketMessage } from '../packet.message'; +import type { CommandHandler, LocateDeviceCommand } from '@agnoc/domain'; + +export class LocateDeviceCommandHandler implements CommandHandler { + readonly forName = 'LocateDeviceCommand'; + + constructor(private readonly packetConnectionFinderService: PacketConnectionFinderService) {} + + async handle(event: LocateDeviceCommand): Promise { + const connection = await this.packetConnectionFinderService.findByDeviceId(event.deviceId); + + if (!connection) { + return; + } + + const response: PacketMessage = await connection.sendAndWait('DEVICE_SEEK_LOCATION_REQ', {}); + + response.assertPayloadName('DEVICE_SEEK_LOCATION_RSP'); + } +} diff --git a/packages/adapter-tcp/src/command-handlers/locate-device.event-handler.ts b/packages/adapter-tcp/src/command-handlers/locate-device.event-handler.ts deleted file mode 100644 index afbe06de..00000000 --- a/packages/adapter-tcp/src/command-handlers/locate-device.event-handler.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { DomainException } from '@agnoc/toolkit'; -import { PacketConnection } from '../aggregate-roots/packet-connection.aggregate-root'; -import type { CommandHandler, Connection, ConnectionRepository, LocateDeviceCommand } from '@agnoc/domain'; - -export class LocateDeviceEventHandler implements CommandHandler { - readonly forName = 'LocateDeviceCommand'; - - constructor(private readonly connectionRepository: ConnectionRepository) {} - - async handle(event: LocateDeviceCommand): Promise { - const connections = await this.connectionRepository.findByDeviceId(event.deviceId); - - if (connections.length === 0) { - throw new DomainException(`Unable to find a connection for the device with id ${event.deviceId.value}`); - } - - const connection = connections.find((connection: Connection): connection is PacketConnection => - PacketConnection.isPacketConnection(connection), - ); - - if (!connection) { - return; - } - - const response = await connection.sendAndWait('DEVICE_SEEK_LOCATION_REQ', {}); - - if (response.packet.payload.opcode.value !== 'DEVICE_SEEK_LOCATION_RSP') { - throw new DomainException(`Unexpected response from device: ${response.packet.payload.opcode.value}`); - } - } -} diff --git a/packages/adapter-tcp/src/connection-device-updater.service.test.ts b/packages/adapter-tcp/src/connection-device-updater.service.test.ts new file mode 100644 index 00000000..3b123685 --- /dev/null +++ b/packages/adapter-tcp/src/connection-device-updater.service.test.ts @@ -0,0 +1,64 @@ +import { Device } from '@agnoc/domain'; +import { givenSomeDeviceProps } from '@agnoc/domain/test-support'; +import { ID } from '@agnoc/toolkit'; +import { Packet } from '@agnoc/transport-tcp'; +import { givenSomePacketProps } from '@agnoc/transport-tcp/test-support'; +import { anything, imock, instance, verify, when } from '@johanblumenberg/ts-mockito'; +import { ConnectionDeviceUpdaterService } from './connection-device-updater.service'; +import type { PacketConnection } from './aggregate-roots/packet-connection.aggregate-root'; +import type { ConnectionRepository, DeviceRepository } from '@agnoc/domain'; + +describe('ConnectionDeviceUpdaterService', function () { + let connectionRepository: ConnectionRepository; + let deviceRepository: DeviceRepository; + let service: ConnectionDeviceUpdaterService; + let connection: PacketConnection; + + beforeEach(function () { + connectionRepository = imock(); + deviceRepository = imock(); + connection = imock(); + service = new ConnectionDeviceUpdaterService(instance(connectionRepository), instance(deviceRepository)); + }); + + describe('#updateFromPacket()', function () { + it('should update device in connection from packet when ids does not match', async function () { + const device = new Device(givenSomeDeviceProps()); + const packet = new Packet({ ...givenSomePacketProps(), deviceId: new ID(1) }); + + when(connection.device).thenReturn(new Device({ ...givenSomeDeviceProps(), id: new ID(2) })); + when(deviceRepository.findOneById(anything())).thenResolve(device); + + await service.updateFromPacket(packet, instance(connection)); + + verify(connection.setDevice(device)).once(); + verify(connectionRepository.saveOne(instance(connection))).once(); + }); + + it('should not update device in connection from packet when ids match', async function () { + const device = new Device(givenSomeDeviceProps()); + const packet = new Packet({ ...givenSomePacketProps(), deviceId: new ID(1) }); + + when(connection.device).thenReturn(new Device({ ...givenSomeDeviceProps(), id: new ID(1) })); + when(deviceRepository.findOneById(anything())).thenResolve(device); + + await service.updateFromPacket(packet, instance(connection)); + + verify(connection.setDevice(anything())).never(); + verify(connectionRepository.saveOne(anything())).never(); + }); + + it('should update device in connection with nothing when packet device id is zero', async function () { + const device = new Device(givenSomeDeviceProps()); + const packet = new Packet({ ...givenSomePacketProps(), deviceId: new ID(0) }); + + when(connection.device).thenReturn(new Device({ ...givenSomeDeviceProps(), id: new ID(1) })); + when(deviceRepository.findOneById(anything())).thenResolve(device); + + await service.updateFromPacket(packet, instance(connection)); + + verify(connection.setDevice(undefined)).once(); + verify(connectionRepository.saveOne(instance(connection))).once(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/connection-device-updater.service.ts b/packages/adapter-tcp/src/connection-device-updater.service.ts new file mode 100644 index 00000000..0005c561 --- /dev/null +++ b/packages/adapter-tcp/src/connection-device-updater.service.ts @@ -0,0 +1,29 @@ +import type { PacketConnection } from './aggregate-roots/packet-connection.aggregate-root'; +import type { ConnectionRepository, DeviceRepository, Device } from '@agnoc/domain'; +import type { ID } from '@agnoc/toolkit'; +import type { Packet } from '@agnoc/transport-tcp'; + +export class ConnectionDeviceUpdaterService { + constructor( + private readonly connectionRepository: ConnectionRepository, + private readonly deviceRepository: DeviceRepository, + ) {} + + async updateFromPacket(packet: Packet, connection: PacketConnection): Promise { + if (!packet.deviceId.equals(connection.device?.id)) { + const device = await this.findDeviceById(packet.deviceId); + + connection.setDevice(device); + + await this.connectionRepository.saveOne(connection); + } + } + + private async findDeviceById(id: ID): Promise { + if (id.value === 0) { + return undefined; + } + + return this.deviceRepository.findOneById(id); + } +} diff --git a/packages/adapter-tcp/src/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.test.ts b/packages/adapter-tcp/src/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.test.ts new file mode 100644 index 00000000..3e5ea18c --- /dev/null +++ b/packages/adapter-tcp/src/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.test.ts @@ -0,0 +1,45 @@ +import { DeviceConnectedDomainEvent } from '@agnoc/domain'; +import { ID } from '@agnoc/toolkit'; +import { anything, deepEqual, imock, instance, verify, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { LockDeviceWhenDeviceIsConnectedEventHandler } from './lock-device-when-device-is-connected-event-handler.event-handler'; +import type { PacketConnection } from '../aggregate-roots/packet-connection.aggregate-root'; +import type { PacketConnectionFinderService } from '../packet-connection-finder.service'; + +describe('LockDeviceWhenDeviceIsConnectedEventHandler', function () { + let packetConnectionFinderService: PacketConnectionFinderService; + let eventHandler: LockDeviceWhenDeviceIsConnectedEventHandler; + let packetConnection: PacketConnection; + + beforeEach(function () { + packetConnectionFinderService = imock(); + eventHandler = new LockDeviceWhenDeviceIsConnectedEventHandler(instance(packetConnectionFinderService)); + packetConnection = imock(); + }); + + it('should define the name', function () { + expect(eventHandler.forName).to.be.equal('DeviceConnectedDomainEvent'); + }); + + describe('#handle()', function () { + it('should lock the device', async function () { + const event = new DeviceConnectedDomainEvent({ aggregateId: new ID(1) }); + + when(packetConnectionFinderService.findByDeviceId(anything())).thenResolve(instance(packetConnection)); + + await eventHandler.handle(event); + + verify(packetConnection.send('DEVICE_CONTROL_LOCK_REQ', deepEqual({}))).once(); + }); + + it('should do nothing when no connection is found', async function () { + const event = new DeviceConnectedDomainEvent({ aggregateId: new ID(1) }); + + when(packetConnectionFinderService.findByDeviceId(anything())).thenResolve(undefined); + + await eventHandler.handle(event); + + verify(packetConnection.send(anything(), anything())).never(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.ts b/packages/adapter-tcp/src/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.ts index 073bd642..8986f5ec 100644 --- a/packages/adapter-tcp/src/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.ts +++ b/packages/adapter-tcp/src/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.ts @@ -1,22 +1,13 @@ -import { DomainException } from '@agnoc/toolkit'; -import { PacketConnection } from '../aggregate-roots/packet-connection.aggregate-root'; -import type { DomainEventHandler, DeviceConnectedDomainEvent, ConnectionRepository, Connection } from '@agnoc/domain'; +import type { PacketConnectionFinderService } from '../packet-connection-finder.service'; +import type { DomainEventHandler, DeviceConnectedDomainEvent } from '@agnoc/domain'; export class LockDeviceWhenDeviceIsConnectedEventHandler implements DomainEventHandler { readonly forName = 'DeviceConnectedDomainEvent'; - constructor(private readonly connectionRepository: ConnectionRepository) {} + constructor(private readonly packetConnectionFinderService: PacketConnectionFinderService) {} async handle(event: DeviceConnectedDomainEvent): Promise { - const connections = await this.connectionRepository.findByDeviceId(event.aggregateId); - - if (connections.length === 0) { - throw new DomainException(`Unable to find a connection for the device with id ${event.aggregateId.value}`); - } - - const connection = connections.find((connection: Connection): connection is PacketConnection => - PacketConnection.isPacketConnection(connection), - ); + const connection = await this.packetConnectionFinderService.findByDeviceId(event.aggregateId); if (!connection) { return; diff --git a/packages/adapter-tcp/src/domain-event-handlers/query-device-info-when-device-is-locked-event-handler.event-handler.test.ts b/packages/adapter-tcp/src/domain-event-handlers/query-device-info-when-device-is-locked-event-handler.event-handler.test.ts new file mode 100644 index 00000000..8ecb3c0c --- /dev/null +++ b/packages/adapter-tcp/src/domain-event-handlers/query-device-info-when-device-is-locked-event-handler.event-handler.test.ts @@ -0,0 +1,70 @@ +import { Device, DeviceLockedDomainEvent, DeviceSystem } from '@agnoc/domain'; +import { givenSomeDeviceProps, givenSomeDeviceSystemProps } from '@agnoc/domain/test-support'; +import { ID } from '@agnoc/toolkit'; +import { imock, instance, when, anything, verify, deepEqual } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { QueryDeviceInfoWhenDeviceIsLockedEventHandler } from './query-device-info-when-device-is-locked-event-handler.event-handler'; +import type { PacketConnection } from '../aggregate-roots/packet-connection.aggregate-root'; +import type { PacketConnectionFinderService } from '../packet-connection-finder.service'; + +describe('QueryDeviceInfoWhenDeviceIsLockedEventHandler', function () { + let packetConnectionFinderService: PacketConnectionFinderService; + let eventHandler: QueryDeviceInfoWhenDeviceIsLockedEventHandler; + let packetConnection: PacketConnection; + + beforeEach(function () { + packetConnectionFinderService = imock(); + eventHandler = new QueryDeviceInfoWhenDeviceIsLockedEventHandler(instance(packetConnectionFinderService)); + packetConnection = imock(); + }); + + it('should define the name', function () { + expect(eventHandler.forName).to.be.equal('DeviceLockedDomainEvent'); + }); + + describe('#handle()', function () { + it('should query device info for type C3490', async function () { + const system = new DeviceSystem({ ...givenSomeDeviceSystemProps(), type: 9 }); + const device = new Device({ ...givenSomeDeviceProps(), system }); + const event = new DeviceLockedDomainEvent({ aggregateId: new ID(1) }); + + when(packetConnectionFinderService.findByDeviceId(anything())).thenResolve(instance(packetConnection)); + when(packetConnection.device).thenReturn(device); + + await eventHandler.handle(event); + + verify(packetConnection.send('DEVICE_STATUS_GETTING_REQ', deepEqual({}))).once(); + verify(packetConnection.send('DEVICE_GET_ALL_GLOBAL_MAP_INFO_REQ', deepEqual({ unk1: 0, unk2: '' }))).once(); + verify(packetConnection.send('DEVICE_GETTIME_REQ', deepEqual({}))).once(); + verify(packetConnection.send('DEVICE_MAPID_GET_GLOBAL_INFO_REQ', deepEqual({ mask: 0x78ff }))).once(); + verify(packetConnection.send('DEVICE_WLAN_INFO_GETTING_REQ', deepEqual({}))).once(); + }); + + it('should query device info for type C3090', async function () { + const system = new DeviceSystem({ ...givenSomeDeviceSystemProps(), type: 3 }); + const device = new Device({ ...givenSomeDeviceProps(), system }); + const event = new DeviceLockedDomainEvent({ aggregateId: new ID(1) }); + + when(packetConnectionFinderService.findByDeviceId(anything())).thenResolve(instance(packetConnection)); + when(packetConnection.device).thenReturn(device); + + await eventHandler.handle(event); + + verify(packetConnection.send('DEVICE_STATUS_GETTING_REQ', deepEqual({}))).once(); + verify(packetConnection.send('DEVICE_GET_ALL_GLOBAL_MAP_INFO_REQ', deepEqual({ unk1: 0, unk2: '' }))).once(); + verify(packetConnection.send('DEVICE_GETTIME_REQ', deepEqual({}))).once(); + verify(packetConnection.send('DEVICE_MAPID_GET_GLOBAL_INFO_REQ', deepEqual({ mask: 0xff }))).once(); + verify(packetConnection.send('DEVICE_WLAN_INFO_GETTING_REQ', deepEqual({}))).once(); + }); + + it('should do nothing when no connection is found', async function () { + const event = new DeviceLockedDomainEvent({ aggregateId: new ID(1) }); + + when(packetConnectionFinderService.findByDeviceId(anything())).thenResolve(undefined); + + await eventHandler.handle(event); + + verify(packetConnection.send(anything(), anything())).never(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/domain-event-handlers/query-device-info-when-device-is-locked-event-handler.event-handler.ts b/packages/adapter-tcp/src/domain-event-handlers/query-device-info-when-device-is-locked-event-handler.event-handler.ts index aba3580d..af1b684f 100644 --- a/packages/adapter-tcp/src/domain-event-handlers/query-device-info-when-device-is-locked-event-handler.event-handler.ts +++ b/packages/adapter-tcp/src/domain-event-handlers/query-device-info-when-device-is-locked-event-handler.event-handler.ts @@ -1,23 +1,14 @@ import { DeviceCapability } from '@agnoc/domain'; -import { DomainException } from '@agnoc/toolkit'; -import { PacketConnection } from '../aggregate-roots/packet-connection.aggregate-root'; -import type { DeviceLockedDomainEvent, DomainEventHandler, Connection, ConnectionRepository } from '@agnoc/domain'; +import type { PacketConnectionFinderService } from '../packet-connection-finder.service'; +import type { DeviceLockedDomainEvent, DomainEventHandler } from '@agnoc/domain'; export class QueryDeviceInfoWhenDeviceIsLockedEventHandler implements DomainEventHandler { readonly forName = 'DeviceLockedDomainEvent'; - constructor(private readonly connectionRepository: ConnectionRepository) {} + constructor(private readonly packetConnectionFinderService: PacketConnectionFinderService) {} async handle(event: DeviceLockedDomainEvent): Promise { - const connections = await this.connectionRepository.findByDeviceId(event.aggregateId); - - if (connections.length === 0) { - throw new DomainException(`Unable to find a connection for the device with id ${event.aggregateId.value}`); - } - - const connection = connections.find((connection: Connection): connection is PacketConnection => - PacketConnection.isPacketConnection(connection), - ); + const connection = await this.packetConnectionFinderService.findByDeviceId(event.aggregateId); if (!connection) { return; diff --git a/packages/adapter-tcp/src/domain-event-handlers/set-device-connected-when-connection-device-changed.event-handler.test.ts b/packages/adapter-tcp/src/domain-event-handlers/set-device-connected-when-connection-device-changed.event-handler.test.ts new file mode 100644 index 00000000..8c9d5b6d --- /dev/null +++ b/packages/adapter-tcp/src/domain-event-handlers/set-device-connected-when-connection-device-changed.event-handler.test.ts @@ -0,0 +1,100 @@ +import { ConnectionDeviceChangedDomainEvent } from '@agnoc/domain'; +import { ID } from '@agnoc/toolkit'; +import { anything, imock, instance, verify, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { SetDeviceAsConnectedWhenConnectionDeviceAddedEventHandler } from './set-device-connected-when-connection-device-changed.event-handler'; +import type { PacketConnection } from '../aggregate-roots/packet-connection.aggregate-root'; +import type { ConnectionRepository, DeviceRepository, Device } from '@agnoc/domain'; + +describe('SetDeviceAsConnectedWhenConnectionDeviceAddedEventHandler', function () { + let connectionRepository: ConnectionRepository; + let deviceRepository: DeviceRepository; + let eventHandler: SetDeviceAsConnectedWhenConnectionDeviceAddedEventHandler; + let packetConnection: PacketConnection; + let device: Device; + + beforeEach(function () { + connectionRepository = imock(); + deviceRepository = imock(); + eventHandler = new SetDeviceAsConnectedWhenConnectionDeviceAddedEventHandler( + instance(connectionRepository), + instance(deviceRepository), + ); + packetConnection = imock(); + device = imock(); + }); + + it('should define the name', function () { + expect(eventHandler.forName).to.be.equal('ConnectionDeviceChangedDomainEvent'); + }); + + describe('#handle()', function () { + it('should set device as connected when there are more than one connection', async function () { + const currentDeviceId = new ID(2); + const event = new ConnectionDeviceChangedDomainEvent({ aggregateId: new ID(1), currentDeviceId }); + + when(connectionRepository.findByDeviceId(anything())).thenResolve([ + instance(packetConnection), + instance(packetConnection), + ]); + when(deviceRepository.findOneById(anything())).thenResolve(instance(device)); + when(packetConnection.connectionType).thenReturn('PACKET'); + when(device.isConnected).thenReturn(false); + + await eventHandler.handle(event); + + verify(connectionRepository.findByDeviceId(currentDeviceId)).once(); + verify(deviceRepository.findOneById(currentDeviceId)).once(); + verify(device.setAsConnected()).once(); + verify(deviceRepository.saveOne(instance(device))).once(); + }); + + it('should do nothing when there is no current device id', async function () { + const event = new ConnectionDeviceChangedDomainEvent({ aggregateId: new ID(1) }); + + await eventHandler.handle(event); + + verify(connectionRepository.findByDeviceId(anything())).never(); + verify(deviceRepository.findOneById(anything())).never(); + verify(device.setAsConnected()).never(); + verify(deviceRepository.saveOne(anything())).never(); + }); + + it('should do nothing when there is only one connection', async function () { + const currentDeviceId = new ID(2); + const event = new ConnectionDeviceChangedDomainEvent({ aggregateId: new ID(1), currentDeviceId }); + + when(connectionRepository.findByDeviceId(anything())).thenResolve([instance(packetConnection)]); + when(deviceRepository.findOneById(anything())).thenResolve(instance(device)); + when(packetConnection.connectionType).thenReturn('PACKET'); + when(device.isConnected).thenReturn(false); + + await eventHandler.handle(event); + + verify(connectionRepository.findByDeviceId(currentDeviceId)).once(); + verify(deviceRepository.findOneById(currentDeviceId)).once(); + verify(device.setAsConnected()).never(); + verify(deviceRepository.saveOne(anything())).never(); + }); + + it('should do nothing when connections are not packet connections', async function () { + const currentDeviceId = new ID(2); + const event = new ConnectionDeviceChangedDomainEvent({ aggregateId: new ID(1), currentDeviceId }); + + when(connectionRepository.findByDeviceId(anything())).thenResolve([ + instance(packetConnection), + instance(packetConnection), + ]); + when(deviceRepository.findOneById(anything())).thenResolve(instance(device)); + when(packetConnection.connectionType).thenReturn('OTHER'); + when(device.isConnected).thenReturn(false); + + await eventHandler.handle(event); + + verify(connectionRepository.findByDeviceId(currentDeviceId)).once(); + verify(deviceRepository.findOneById(currentDeviceId)).once(); + verify(device.setAsConnected()).never(); + verify(deviceRepository.saveOne(anything())).never(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/domain-event-handlers/set-device-connected-when-connection-device-changed.domain-event.ts b/packages/adapter-tcp/src/domain-event-handlers/set-device-connected-when-connection-device-changed.event-handler.ts similarity index 67% rename from packages/adapter-tcp/src/domain-event-handlers/set-device-connected-when-connection-device-changed.domain-event.ts rename to packages/adapter-tcp/src/domain-event-handlers/set-device-connected-when-connection-device-changed.event-handler.ts index ef44589c..9326b4f3 100644 --- a/packages/adapter-tcp/src/domain-event-handlers/set-device-connected-when-connection-device-changed.domain-event.ts +++ b/packages/adapter-tcp/src/domain-event-handlers/set-device-connected-when-connection-device-changed.event-handler.ts @@ -1,11 +1,13 @@ +import { PacketConnection } from '../aggregate-roots/packet-connection.aggregate-root'; import type { DomainEventHandler, ConnectionRepository, DeviceRepository, ConnectionDeviceChangedDomainEvent, + Connection, } from '@agnoc/domain'; -export class SetDeviceAsConnectedWhenConnectionDeviceAddedDomainEventHandler implements DomainEventHandler { +export class SetDeviceAsConnectedWhenConnectionDeviceAddedEventHandler implements DomainEventHandler { readonly forName = 'ConnectionDeviceChangedDomainEvent'; constructor( @@ -17,10 +19,13 @@ export class SetDeviceAsConnectedWhenConnectionDeviceAddedDomainEventHandler imp if (event.currentDeviceId) { const connections = await this.connectionRepository.findByDeviceId(event.currentDeviceId); const device = await this.deviceRepository.findOneById(event.currentDeviceId); + const packetConnections = connections.filter((connection: Connection): connection is PacketConnection => + PacketConnection.isPacketConnection(connection), + ); // This is a hack to only mark the device as connected if there is more than one connection. // Here we should check that the connections are from the same ip address. - if (connections.length > 1 && device && !device.isConnected) { + if (packetConnections.length > 1 && device && !device.isConnected) { device.setAsConnected(); await this.deviceRepository.saveOne(device); diff --git a/packages/adapter-tcp/src/factories/connection.factory.test.ts b/packages/adapter-tcp/src/factories/connection.factory.test.ts new file mode 100644 index 00000000..248b0b81 --- /dev/null +++ b/packages/adapter-tcp/src/factories/connection.factory.test.ts @@ -0,0 +1,32 @@ +import { Connection } from '@agnoc/domain'; +import { ID } from '@agnoc/toolkit'; +import { PacketSocket } from '@agnoc/transport-tcp'; +import { imock, instance } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { PacketConnectionFactory } from './connection.factory'; +import type { PacketEventBus } from '../packet.event-bus'; +import type { PacketFactory, PacketMapper } from '@agnoc/transport-tcp'; + +describe('PacketConnectionFactory', function () { + let packetEventBus: PacketEventBus; + let packetFactory: PacketFactory; + let packetMapper: PacketMapper; + let connectionFactory: PacketConnectionFactory; + + beforeEach(function () { + packetEventBus = imock(); + packetFactory = imock(); + packetMapper = imock(); + connectionFactory = new PacketConnectionFactory(instance(packetEventBus), instance(packetFactory)); + }); + + describe('#create()', function () { + it('should return a PacketConnection', function () { + const id = ID.generate(); + const connection = connectionFactory.create({ id, socket: new PacketSocket(packetMapper) }); + + expect(connection).to.be.instanceOf(Connection); + expect(connection.id.equals(id)).to.be.true; + }); + }); +}); diff --git a/packages/adapter-tcp/src/index.ts b/packages/adapter-tcp/src/index.ts index e397dcd6..bac62133 100644 --- a/packages/adapter-tcp/src/index.ts +++ b/packages/adapter-tcp/src/index.ts @@ -4,6 +4,6 @@ export * from './mappers/device-fan-speed.mapper'; export * from './mappers/device-mode.mapper'; export * from './mappers/device-order.mapper'; export * from './mappers/device-state.mapper'; -export * from './mappers/device-voice.mapper'; +export * from './mappers/voice-setting.mapper'; export * from './mappers/device-water-level.mapper'; export * from './tcp.server'; diff --git a/packages/adapter-tcp/src/mappers/clean-mode.mapper.test.ts b/packages/adapter-tcp/src/mappers/clean-mode.mapper.test.ts new file mode 100644 index 00000000..dcc8db5d --- /dev/null +++ b/packages/adapter-tcp/src/mappers/clean-mode.mapper.test.ts @@ -0,0 +1,29 @@ +import { CleanMode, CleanModeValue } from '@agnoc/domain'; +import { expect } from 'chai'; +import { CleanModeMapper } from './clean-mode.mapper'; + +describe('CleanModeMapper', function () { + let mapper: CleanModeMapper; + + beforeEach(function () { + mapper = new CleanModeMapper(); + }); + + describe('#toDomain()', function () { + it('should return a CleanMode', function () { + const cleanMode = mapper.toDomain(1); + + expect(cleanMode).to.be.instanceOf(CleanMode); + expect(cleanMode.value).to.be.equal(CleanModeValue.Auto); + }); + }); + + describe('#fromDomain()', function () { + it('should return a number', function () { + const cleanMode = new CleanMode(CleanModeValue.Auto); + const cleanModeValue = mapper.fromDomain(cleanMode); + + expect(cleanModeValue).to.be.equal(1); + }); + }); +}); diff --git a/packages/adapter-tcp/src/mappers/device-battery.mapper.test.ts b/packages/adapter-tcp/src/mappers/device-battery.mapper.test.ts new file mode 100644 index 00000000..a4cfb1ba --- /dev/null +++ b/packages/adapter-tcp/src/mappers/device-battery.mapper.test.ts @@ -0,0 +1,43 @@ +import { DeviceBattery } from '@agnoc/domain'; +import { expect } from 'chai'; +import { DeviceBatteryMapper } from './device-battery.mapper'; + +describe('DeviceBatteryMapper', function () { + let mapper: DeviceBatteryMapper; + + beforeEach(function () { + mapper = new DeviceBatteryMapper(); + }); + + describe('#toDomain()', function () { + it('should return a DeviceBattery', function () { + const deviceBattery = mapper.toDomain(150); + + expect(deviceBattery).to.be.instanceOf(DeviceBattery); + expect(deviceBattery.value).to.be.equal(50); + }); + + it('should return a DeviceBattery with minimum value when below minimum', function () { + const deviceBattery = mapper.toDomain(-50); + + expect(deviceBattery).to.be.instanceOf(DeviceBattery); + expect(deviceBattery.value).to.be.equal(0); + }); + + it('should return a DeviceBattery with maximum value when above maximum', function () { + const deviceBattery = mapper.toDomain(250); + + expect(deviceBattery).to.be.instanceOf(DeviceBattery); + expect(deviceBattery.value).to.be.equal(100); + }); + }); + + describe('#fromDomain()', function () { + it('should return a number', function () { + const deviceBattery = new DeviceBattery(50); + const deviceBatteryValue = mapper.fromDomain(deviceBattery); + + expect(deviceBatteryValue).to.be.equal(150); + }); + }); +}); diff --git a/packages/adapter-tcp/src/mappers/device-error.mapper.test.ts b/packages/adapter-tcp/src/mappers/device-error.mapper.test.ts new file mode 100644 index 00000000..d11f46f4 --- /dev/null +++ b/packages/adapter-tcp/src/mappers/device-error.mapper.test.ts @@ -0,0 +1,31 @@ +import { DeviceError, DeviceErrorValue } from '@agnoc/domain'; +import { DomainException, NotImplementedException } from '@agnoc/toolkit'; +import { expect } from 'chai'; +import { DeviceErrorMapper } from './device-error.mapper'; + +describe('DeviceErrorMapper', function () { + let mapper: DeviceErrorMapper; + + beforeEach(function () { + mapper = new DeviceErrorMapper(); + }); + + describe('#toDomain()', function () { + it('should return a DeviceError', function () { + const deviceError = mapper.toDomain(0); + + expect(deviceError).to.be.instanceOf(DeviceError); + expect(deviceError.value).to.be.equal(DeviceErrorValue.None); + }); + + it('should throw an error when device mode is unknown', function () { + expect(() => mapper.toDomain(999)).to.throw(DomainException, `Unable to map error code '999' to domain value`); + }); + }); + + describe('#fromDomain()', function () { + it('should throw an error', function () { + expect(() => mapper.fromDomain()).to.throw(NotImplementedException, 'DeviceErrorMapper.fromDomain'); + }); + }); +}); diff --git a/packages/adapter-tcp/src/mappers/device-error.mapper.ts b/packages/adapter-tcp/src/mappers/device-error.mapper.ts index 30593c0c..895dbaa8 100644 --- a/packages/adapter-tcp/src/mappers/device-error.mapper.ts +++ b/packages/adapter-tcp/src/mappers/device-error.mapper.ts @@ -59,6 +59,6 @@ export class DeviceErrorMapper implements Mapper { } fromDomain(): never { - throw new NotImplementedException('DeviceErrorMapper.toRobot'); + throw new NotImplementedException('DeviceErrorMapper.fromDomain'); } } diff --git a/packages/adapter-tcp/src/mappers/device-fan-speed.mapper.test.ts b/packages/adapter-tcp/src/mappers/device-fan-speed.mapper.test.ts new file mode 100644 index 00000000..751e7284 --- /dev/null +++ b/packages/adapter-tcp/src/mappers/device-fan-speed.mapper.test.ts @@ -0,0 +1,29 @@ +import { DeviceFanSpeed, DeviceFanSpeedValue } from '@agnoc/domain'; +import { expect } from 'chai'; +import { DeviceFanSpeedMapper } from './device-fan-speed.mapper'; + +describe('DeviceFanSpeedMapper', function () { + let mapper: DeviceFanSpeedMapper; + + beforeEach(function () { + mapper = new DeviceFanSpeedMapper(); + }); + + describe('#toDomain()', function () { + it('should return a DeviceFanSpeed', function () { + const deviceFanSpeed = mapper.toDomain(0); + + expect(deviceFanSpeed).to.be.instanceOf(DeviceFanSpeed); + expect(deviceFanSpeed.value).to.be.equal(DeviceFanSpeedValue.Off); + }); + }); + + describe('#fromDomain()', function () { + it('should return a number', function () { + const deviceFanSpeed = new DeviceFanSpeed(DeviceFanSpeedValue.Off); + const deviceFanSpeedValue = mapper.fromDomain(deviceFanSpeed); + + expect(deviceFanSpeedValue).to.be.equal(0); + }); + }); +}); diff --git a/packages/adapter-tcp/src/mappers/device-mode.mapper.test.ts b/packages/adapter-tcp/src/mappers/device-mode.mapper.test.ts new file mode 100644 index 00000000..a34e965e --- /dev/null +++ b/packages/adapter-tcp/src/mappers/device-mode.mapper.test.ts @@ -0,0 +1,52 @@ +import { DeviceMode, DeviceModeValue } from '@agnoc/domain'; +import { DomainException, NotImplementedException } from '@agnoc/toolkit'; +import { expect } from 'chai'; +import { DeviceModeMapper } from './device-mode.mapper'; + +describe('DeviceModeMapper', function () { + let mapper: DeviceModeMapper; + + beforeEach(function () { + mapper = new DeviceModeMapper(); + }); + + describe('#toDomain()', function () { + it('should return a none device mode', function () { + const deviceMode = mapper.toDomain(0); + + expect(deviceMode).to.be.instanceOf(DeviceMode); + expect(deviceMode.value).to.be.equal(DeviceModeValue.None); + }); + + it('should return a zone device mode', function () { + const deviceMode = mapper.toDomain(30); + + expect(deviceMode).to.be.instanceOf(DeviceMode); + expect(deviceMode.value).to.be.equal(DeviceModeValue.Zone); + }); + + it('should return an spot device mode', function () { + const deviceMode = mapper.toDomain(7); + + expect(deviceMode).to.be.instanceOf(DeviceMode); + expect(deviceMode.value).to.be.equal(DeviceModeValue.Spot); + }); + + it('should return a mop device mode', function () { + const deviceMode = mapper.toDomain(36); + + expect(deviceMode).to.be.instanceOf(DeviceMode); + expect(deviceMode.value).to.be.equal(DeviceModeValue.Mop); + }); + + it('should throw an error when device mode is unknown', function () { + expect(() => mapper.toDomain(999)).to.throw(DomainException, 'Unable to map device mode from mode 999'); + }); + }); + + describe('#fromDomain()', function () { + it('should throw an error', function () { + expect(() => mapper.fromDomain()).to.throw(NotImplementedException, 'DeviceModeMapper.fromDomain'); + }); + }); +}); diff --git a/packages/adapter-tcp/src/mappers/device-mode.mapper.ts b/packages/adapter-tcp/src/mappers/device-mode.mapper.ts index 282dd560..3a55478d 100644 --- a/packages/adapter-tcp/src/mappers/device-mode.mapper.ts +++ b/packages/adapter-tcp/src/mappers/device-mode.mapper.ts @@ -28,6 +28,6 @@ export class DeviceModeMapper implements Mapper { } fromDomain(): number { - throw new NotImplementedException('DeviceModeMapper.toRobot'); + throw new NotImplementedException(`${this.constructor.name}.fromDomain`); } } diff --git a/packages/adapter-tcp/src/mappers/device-order.mapper.test.ts b/packages/adapter-tcp/src/mappers/device-order.mapper.test.ts new file mode 100644 index 00000000..d64d74d0 --- /dev/null +++ b/packages/adapter-tcp/src/mappers/device-order.mapper.test.ts @@ -0,0 +1,179 @@ +import { + DeviceFanSpeed, + DeviceFanSpeedValue, + DeviceWaterLevel, + DeviceWaterLevelValue, + CleanMode, + CleanModeValue, + WeekDay, + WeekDayValue, + DeviceOrder, + DeviceTime, +} from '@agnoc/domain'; +import { ArgumentNotProvidedException, ID } from '@agnoc/toolkit'; +import { anything, imock, instance, verify, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { DeviceOrderMapper } from './device-order.mapper'; +import type { CleanModeMapper } from './clean-mode.mapper'; +import type { DeviceFanSpeedMapper } from './device-fan-speed.mapper'; +import type { DeviceWaterLevelMapper } from './device-water-level.mapper'; +import type { WeekDayListMapper } from './week-day-list.mapper'; + +describe('DeviceOrderMapper', function () { + let deviceFanSpeedMapper: DeviceFanSpeedMapper; + let deviceWaterLevelMapper: DeviceWaterLevelMapper; + let cleanModeMapper: CleanModeMapper; + let weekDayListMapper: WeekDayListMapper; + let mapper: DeviceOrderMapper; + + beforeEach(function () { + deviceFanSpeedMapper = imock(); + deviceWaterLevelMapper = imock(); + cleanModeMapper = imock(); + weekDayListMapper = imock(); + mapper = new DeviceOrderMapper( + instance(deviceFanSpeedMapper), + instance(deviceWaterLevelMapper), + instance(cleanModeMapper), + instance(weekDayListMapper), + ); + }); + + describe('#toDomain()', function () { + it('should return a DeviceOrder', function () { + when(deviceFanSpeedMapper.toDomain(anything())).thenReturn(new DeviceFanSpeed(DeviceFanSpeedValue.Off)); + when(deviceWaterLevelMapper.toDomain(anything())).thenReturn(new DeviceWaterLevel(DeviceWaterLevelValue.Off)); + when(cleanModeMapper.toDomain(anything())).thenReturn(new CleanMode(CleanModeValue.Auto)); + when(weekDayListMapper.toDomain(anything())).thenReturn([new WeekDay(WeekDayValue.Monday)]); + + const deviceOrder = mapper.toDomain({ + orderId: 1, + enable: true, + repeat: true, + weekDay: 1, + dayTime: 90, + cleanInfo: { + mapHeadId: 2, + planId: 3, + cleanMode: 4, + windPower: 5, + waterLevel: 6, + twiceClean: true, + }, + }); + + expect(deviceOrder).to.be.instanceOf(DeviceOrder); + expect(deviceOrder.id.equals(new ID(1))).to.be.true; + expect(deviceOrder.mapId.equals(new ID(2))).to.be.true; + expect(deviceOrder.planId.equals(new ID(3))).to.be.true; + expect(deviceOrder.isEnabled).to.be.true; + expect(deviceOrder.isRepeatable).to.be.true; + expect(deviceOrder.isDeepClean).to.be.true; + expect(deviceOrder.weekDays).to.deep.contain(new WeekDay(WeekDayValue.Monday)); + expect(deviceOrder.time.equals(new DeviceTime({ hours: 1, minutes: 30 }))).to.be.true; + expect(deviceOrder.cleanMode.equals(new CleanMode(CleanModeValue.Auto))).to.be.true; + expect(deviceOrder.fanSpeed.equals(new DeviceFanSpeed(DeviceFanSpeedValue.Off))).to.be.true; + expect(deviceOrder.waterLevel.equals(new DeviceWaterLevel(DeviceWaterLevelValue.Off))).to.be.true; + + verify(deviceFanSpeedMapper.toDomain(5)).once(); + verify(deviceWaterLevelMapper.toDomain(6)).once(); + verify(cleanModeMapper.toDomain(4)).once(); + verify(weekDayListMapper.toDomain(1)).once(); + }); + + it('should return a DeviceOrder when order list has no water level', function () { + when(deviceFanSpeedMapper.toDomain(anything())).thenReturn(new DeviceFanSpeed(DeviceFanSpeedValue.Off)); + when(cleanModeMapper.toDomain(anything())).thenReturn(new CleanMode(CleanModeValue.Auto)); + when(weekDayListMapper.toDomain(anything())).thenReturn([new WeekDay(WeekDayValue.Monday)]); + + const deviceOrder = mapper.toDomain({ + orderId: 1, + enable: true, + repeat: true, + weekDay: 1, + dayTime: 90, + cleanInfo: { + mapHeadId: 2, + planId: 3, + cleanMode: 4, + windPower: 5, + twiceClean: true, + }, + }); + + expect(deviceOrder).to.be.instanceOf(DeviceOrder); + expect(deviceOrder.id.equals(new ID(1))).to.be.true; + expect(deviceOrder.mapId.equals(new ID(2))).to.be.true; + expect(deviceOrder.planId.equals(new ID(3))).to.be.true; + expect(deviceOrder.isEnabled).to.be.true; + expect(deviceOrder.isRepeatable).to.be.true; + expect(deviceOrder.isDeepClean).to.be.true; + expect(deviceOrder.weekDays).to.deep.contain(new WeekDay(WeekDayValue.Monday)); + expect(deviceOrder.time.equals(new DeviceTime({ hours: 1, minutes: 30 }))).to.be.true; + expect(deviceOrder.cleanMode.equals(new CleanMode(CleanModeValue.Auto))).to.be.true; + expect(deviceOrder.fanSpeed.equals(new DeviceFanSpeed(DeviceFanSpeedValue.Off))).to.be.true; + expect(deviceOrder.waterLevel.equals(new DeviceWaterLevel(DeviceWaterLevelValue.Off))).to.be.true; + + verify(deviceFanSpeedMapper.toDomain(5)).once(); + verify(deviceWaterLevelMapper.toDomain(anything())).never(); + verify(cleanModeMapper.toDomain(4)).once(); + verify(weekDayListMapper.toDomain(1)).once(); + }); + + it("should throw an error when 'cleanInfo' is not defined", function () { + expect(() => + mapper.toDomain({ + orderId: 1, + enable: true, + repeat: true, + weekDay: 1, + dayTime: 90, + }), + ).to.throw(ArgumentNotProvidedException, 'Unable to read clean info from order list'); + }); + }); + + describe('#fromDomain()', function () { + it('should return an order list', function () { + const deviceOrder = new DeviceOrder({ + id: new ID(1), + mapId: new ID(2), + planId: new ID(3), + isEnabled: true, + isRepeatable: true, + isDeepClean: true, + weekDays: [new WeekDay(WeekDayValue.Monday)], + time: new DeviceTime({ hours: 1, minutes: 30 }), + cleanMode: new CleanMode(CleanModeValue.Auto), + fanSpeed: new DeviceFanSpeed(DeviceFanSpeedValue.Off), + waterLevel: new DeviceWaterLevel(DeviceWaterLevelValue.Off), + }); + + when(deviceFanSpeedMapper.fromDomain(anything())).thenReturn(5); + when(deviceWaterLevelMapper.fromDomain(anything())).thenReturn(6); + when(cleanModeMapper.fromDomain(anything())).thenReturn(4); + when(weekDayListMapper.fromDomain(anything())).thenReturn(1); + + const orderList = mapper.fromDomain(deviceOrder); + + expect(orderList.orderId).to.be.equal(1); + expect(orderList.enable).to.be.true; + expect(orderList.repeat).to.be.true; + expect(orderList.weekDay).to.be.equal(1); + expect(orderList.dayTime).to.be.equal(90); + expect(orderList.cleanInfo).to.be.deep.equal({ + mapHeadId: 2, + planId: 3, + cleanMode: 4, + windPower: 5, + waterLevel: 6, + twiceClean: true, + }); + + verify(deviceFanSpeedMapper.fromDomain(deviceOrder.fanSpeed)).once(); + verify(deviceWaterLevelMapper.fromDomain(deviceOrder.waterLevel)).once(); + verify(cleanModeMapper.fromDomain(deviceOrder.cleanMode)).once(); + verify(weekDayListMapper.fromDomain(deviceOrder.weekDays)).once(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/mappers/device-state.mapper.test.ts b/packages/adapter-tcp/src/mappers/device-state.mapper.test.ts new file mode 100644 index 00000000..4e67af52 --- /dev/null +++ b/packages/adapter-tcp/src/mappers/device-state.mapper.test.ts @@ -0,0 +1,76 @@ +import { DeviceState, DeviceStateValue } from '@agnoc/domain'; +import { DomainException, NotImplementedException } from '@agnoc/toolkit'; +import { expect } from 'chai'; +import { DeviceStateMapper } from './device-state.mapper'; + +describe('DeviceStateMapper', function () { + let mapper: DeviceStateMapper; + + beforeEach(function () { + mapper = new DeviceStateMapper(); + }); + + describe('#toDomain()', function () { + it('should return an error device state', function () { + const deviceState = mapper.toDomain({ chargeStatus: true, type: 1, workMode: 0 }); + + expect(deviceState).to.be.instanceOf(DeviceState); + expect(deviceState.value).to.be.equal(DeviceStateValue.Error); + }); + + it('should return a manual control device state', function () { + const deviceState = mapper.toDomain({ chargeStatus: false, type: 0, workMode: 2 }); + + expect(deviceState).to.be.instanceOf(DeviceState); + expect(deviceState.value).to.be.equal(DeviceStateValue.ManualControl); + }); + + it('should return a returning device state', function () { + const deviceState = mapper.toDomain({ chargeStatus: false, type: 0, workMode: 5 }); + + expect(deviceState).to.be.instanceOf(DeviceState); + expect(deviceState.value).to.be.equal(DeviceStateValue.Returning); + }); + + it('should return a paused device state', function () { + const deviceState = mapper.toDomain({ chargeStatus: false, type: 0, workMode: 4 }); + + expect(deviceState).to.be.instanceOf(DeviceState); + expect(deviceState.value).to.be.equal(DeviceStateValue.Paused); + }); + + it('should return a cleaning device state', function () { + const deviceState = mapper.toDomain({ chargeStatus: false, type: 0, workMode: 1 }); + + expect(deviceState).to.be.instanceOf(DeviceState); + expect(deviceState.value).to.be.equal(DeviceStateValue.Cleaning); + }); + + it('should return a docked device state', function () { + const deviceState = mapper.toDomain({ chargeStatus: true, type: 0, workMode: 0 }); + + expect(deviceState).to.be.instanceOf(DeviceState); + expect(deviceState.value).to.be.equal(DeviceStateValue.Docked); + }); + + it('should return a idle device state', function () { + const deviceState = mapper.toDomain({ chargeStatus: false, type: 0, workMode: 0 }); + + expect(deviceState).to.be.instanceOf(DeviceState); + expect(deviceState.value).to.be.equal(DeviceStateValue.Idle); + }); + + it('should throw an error when device state is unknown', function () { + expect(() => mapper.toDomain({ chargeStatus: false, type: 0, workMode: 100 })).to.throw( + DomainException, + 'Unable to map device state from data: {"chargeStatus":false,"type":0,"workMode":100}', + ); + }); + }); + + describe('#fromDomain()', function () { + it('should throw an error', function () { + expect(() => mapper.fromDomain()).to.throw(NotImplementedException, 'DeviceStateMapper.fromDomain'); + }); + }); +}); diff --git a/packages/adapter-tcp/src/mappers/device-state.mapper.ts b/packages/adapter-tcp/src/mappers/device-state.mapper.ts index 3a5956f9..e1819f5b 100644 --- a/packages/adapter-tcp/src/mappers/device-state.mapper.ts +++ b/packages/adapter-tcp/src/mappers/device-state.mapper.ts @@ -81,6 +81,6 @@ export class DeviceStateMapper implements Mapper { } fromDomain(): RobotState { - throw new NotImplementedException('DeviceStateMapper.toRobot'); + throw new NotImplementedException(`${this.constructor.name}.fromDomain`); } } diff --git a/packages/adapter-tcp/src/mappers/device-water-level.mapper.test.ts b/packages/adapter-tcp/src/mappers/device-water-level.mapper.test.ts new file mode 100644 index 00000000..1d43344f --- /dev/null +++ b/packages/adapter-tcp/src/mappers/device-water-level.mapper.test.ts @@ -0,0 +1,29 @@ +import { DeviceWaterLevel, DeviceWaterLevelValue } from '@agnoc/domain'; +import { expect } from 'chai'; +import { DeviceWaterLevelMapper } from './device-water-level.mapper'; + +describe('DeviceWaterLevelMapper', function () { + let mapper: DeviceWaterLevelMapper; + + beforeEach(function () { + mapper = new DeviceWaterLevelMapper(); + }); + + describe('#toDomain()', function () { + it('should return a DeviceWaterLevel', function () { + const deviceWaterLevel = mapper.toDomain(10); + + expect(deviceWaterLevel).to.be.instanceOf(DeviceWaterLevel); + expect(deviceWaterLevel.value).to.be.equal(DeviceWaterLevelValue.Off); + }); + }); + + describe('#fromDomain()', function () { + it('should return a number', function () { + const deviceWaterLevel = new DeviceWaterLevel(DeviceWaterLevelValue.Off); + const deviceWaterLevelValue = mapper.fromDomain(deviceWaterLevel); + + expect(deviceWaterLevelValue).to.be.equal(10); + }); + }); +}); diff --git a/packages/adapter-tcp/src/mappers/voice-setting.mapper.test.ts b/packages/adapter-tcp/src/mappers/voice-setting.mapper.test.ts new file mode 100644 index 00000000..d0194d8f --- /dev/null +++ b/packages/adapter-tcp/src/mappers/voice-setting.mapper.test.ts @@ -0,0 +1,39 @@ +import { VoiceSetting } from '@agnoc/domain'; +import { expect } from 'chai'; +import { VoiceSettingMapper } from './voice-setting.mapper'; + +describe('VoiceSettingMapper', function () { + let mapper: VoiceSettingMapper; + + beforeEach(function () { + mapper = new VoiceSettingMapper(); + }); + + describe('#toDomain()', function () { + it('should return a VoiceSetting', function () { + const voiceSetting = mapper.toDomain({ isEnabled: true, volume: 6 }); + + expect(voiceSetting).to.be.instanceOf(VoiceSetting); + expect(voiceSetting.isEnabled).to.be.equal(true); + expect(voiceSetting.volume).to.be.equal(50); + }); + + it('should return a VoiceSetting with defaults', function () { + const voiceSetting = mapper.toDomain({ isEnabled: undefined, volume: undefined }); + + expect(voiceSetting).to.be.instanceOf(VoiceSetting); + expect(voiceSetting.isEnabled).to.be.equal(false); + expect(voiceSetting.volume).to.be.equal(0); + }); + }); + + describe('#fromDomain()', function () { + it('should return a number', function () { + const voiceSetting = new VoiceSetting({ isEnabled: true, volume: 50 }); + const voiceSettingValue = mapper.fromDomain(voiceSetting); + + expect(voiceSettingValue.isEnabled).to.be.equal(true); + expect(voiceSettingValue.volume).to.be.equal(6); + }); + }); +}); diff --git a/packages/adapter-tcp/src/mappers/device-voice.mapper.ts b/packages/adapter-tcp/src/mappers/voice-setting.mapper.ts similarity index 91% rename from packages/adapter-tcp/src/mappers/device-voice.mapper.ts rename to packages/adapter-tcp/src/mappers/voice-setting.mapper.ts index 7b114115..3a17ae7f 100644 --- a/packages/adapter-tcp/src/mappers/device-voice.mapper.ts +++ b/packages/adapter-tcp/src/mappers/voice-setting.mapper.ts @@ -19,7 +19,7 @@ export interface RobotVoice { volume: number | null | undefined; } -export class DeviceVoiceMapper implements Mapper { +export class VoiceSettingMapper implements Mapper { toDomain({ isEnabled, volume }: RobotVoice): VoiceSetting { return new VoiceSetting({ isEnabled: isEnabled ?? false, diff --git a/packages/adapter-tcp/src/mappers/week-day-list.mapper.test.ts b/packages/adapter-tcp/src/mappers/week-day-list.mapper.test.ts index 6519d093..a6b3e714 100644 --- a/packages/adapter-tcp/src/mappers/week-day-list.mapper.test.ts +++ b/packages/adapter-tcp/src/mappers/week-day-list.mapper.test.ts @@ -3,10 +3,16 @@ import { expect } from 'chai'; import { WeekDayDomainToRobotMap, WeekDayListMapper } from './week-day-list.mapper'; describe('WeekDayListMapper', function () { + let mapper: WeekDayListMapper; + + beforeEach(function () { + mapper = new WeekDayListMapper(); + }); + describe('#toDomain()', function () { it('should return an array of WeekDay', function () { const weekDay = WeekDayDomainToRobotMap.Monday | WeekDayDomainToRobotMap.Wednesday; - const weekDayList = new WeekDayListMapper().toDomain(weekDay); + const weekDayList = mapper.toDomain(weekDay); expect(weekDayList.length).to.be.equal(2); expect(weekDayList[0]).to.be.instanceOf(WeekDay); @@ -19,7 +25,7 @@ describe('WeekDayListMapper', function () { describe('#fromDomain()', function () { it('should return a number', function () { const weekDayList = [new WeekDay(WeekDayValue.Monday), new WeekDay(WeekDayValue.Wednesday)]; - const weekDay = new WeekDayListMapper().fromDomain(weekDayList); + const weekDay = mapper.fromDomain(weekDayList); expect(weekDay).to.be.equal(WeekDayDomainToRobotMap.Monday | WeekDayDomainToRobotMap.Wednesday); }); diff --git a/packages/adapter-tcp/src/packet-connection-finder.service.test.ts b/packages/adapter-tcp/src/packet-connection-finder.service.test.ts new file mode 100644 index 00000000..c0413a9c --- /dev/null +++ b/packages/adapter-tcp/src/packet-connection-finder.service.test.ts @@ -0,0 +1,53 @@ +import { DomainException, ID } from '@agnoc/toolkit'; +import { imock, instance, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { PacketConnectionFinderService } from './packet-connection-finder.service'; +import type { PacketConnection } from './aggregate-roots/packet-connection.aggregate-root'; +import type { ConnectionRepository } from '@agnoc/domain'; + +describe('PacketConnectionFinderService', function () { + let connectionRepository: ConnectionRepository; + let service: PacketConnectionFinderService; + let packetConnection: PacketConnection; + + beforeEach(function () { + connectionRepository = imock(); + service = new PacketConnectionFinderService(instance(connectionRepository)); + packetConnection = imock(); + }); + + describe('#findByDeviceId()', function () { + it('should find a connection by device id when it is a packet connection', async function () { + const deviceId = new ID(1); + + when(connectionRepository.findByDeviceId(deviceId)).thenResolve([instance(packetConnection)]); + when(packetConnection.connectionType).thenReturn('PACKET'); + + const ret = await service.findByDeviceId(deviceId); + + expect(ret).to.equal(instance(packetConnection)); + }); + + it('should not find anything when is it not a packet connection', async function () { + const deviceId = new ID(1); + + when(connectionRepository.findByDeviceId(deviceId)).thenResolve([instance(packetConnection)]); + when(packetConnection.connectionType).thenReturn('OTHER'); + + const ret = await service.findByDeviceId(deviceId); + + expect(ret).to.equal(undefined); + }); + + it('should throw an error when no connection is found', async function () { + const deviceId = new ID(1); + + when(connectionRepository.findByDeviceId(deviceId)).thenResolve([]); + + await expect(service.findByDeviceId(deviceId)).to.be.rejectedWith( + DomainException, + 'Unable to find a connection for the device with id 1', + ); + }); + }); +}); diff --git a/packages/adapter-tcp/src/packet-connection-finder.service.ts b/packages/adapter-tcp/src/packet-connection-finder.service.ts new file mode 100644 index 00000000..1bbe641e --- /dev/null +++ b/packages/adapter-tcp/src/packet-connection-finder.service.ts @@ -0,0 +1,20 @@ +import { DomainException } from '@agnoc/toolkit'; +import { PacketConnection } from './aggregate-roots/packet-connection.aggregate-root'; +import type { ConnectionRepository, Connection } from '@agnoc/domain'; +import type { ID } from '@agnoc/toolkit'; + +export class PacketConnectionFinderService { + constructor(private readonly connectionRepository: ConnectionRepository) {} + + async findByDeviceId(deviceId: ID): Promise { + const connections = await this.connectionRepository.findByDeviceId(deviceId); + + if (connections.length === 0) { + throw new DomainException(`Unable to find a connection for the device with id ${deviceId.value}`); + } + + return connections.find((connection: Connection): connection is PacketConnection => + PacketConnection.isPacketConnection(connection), + ); + } +} diff --git a/packages/adapter-tcp/src/packet-event-handlers/client-heartbeat.event-handler.test.ts b/packages/adapter-tcp/src/packet-event-handlers/client-heartbeat.event-handler.test.ts new file mode 100644 index 00000000..90f721f8 --- /dev/null +++ b/packages/adapter-tcp/src/packet-event-handlers/client-heartbeat.event-handler.test.ts @@ -0,0 +1,26 @@ +import { deepEqual, imock, instance, verify } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { ClientHeartbeatEventHandler } from './client-heartbeat.event-handler'; +import type { PacketMessage } from '../packet.message'; + +describe('ClientHeartbeatEventHandler', function () { + let eventHandler: ClientHeartbeatEventHandler; + let packetMessage: PacketMessage<'CLIENT_HEARTBEAT_REQ'>; + + beforeEach(function () { + eventHandler = new ClientHeartbeatEventHandler(); + packetMessage = imock(); + }); + + it('should define the name', function () { + expect(eventHandler.forName).to.be.equal('CLIENT_HEARTBEAT_REQ'); + }); + + describe('#handle()', function () { + it('should respond to the message', async function () { + await eventHandler.handle(instance(packetMessage)); + + verify(packetMessage.respond('CLIENT_HEARTBEAT_RSP', deepEqual({}))).once(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/packet-event-handlers/client-login.event-handler.test.ts b/packages/adapter-tcp/src/packet-event-handlers/client-login.event-handler.test.ts new file mode 100644 index 00000000..d5dada18 --- /dev/null +++ b/packages/adapter-tcp/src/packet-event-handlers/client-login.event-handler.test.ts @@ -0,0 +1,53 @@ +import { OPCode, Packet, Payload } from '@agnoc/transport-tcp'; +import { givenSomePacketProps } from '@agnoc/transport-tcp/test-support'; +import { deepEqual, imock, instance, verify, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { ClientLoginEventHandler } from './client-login.event-handler'; +import type { PacketMessage } from '../packet.message'; +import type { Device } from '@agnoc/domain'; + +describe('ClientLoginEventHandler', function () { + let eventHandler: ClientLoginEventHandler; + let packetMessage: PacketMessage<'CLIENT_ONLINE_REQ'>; + let device: Device; + + beforeEach(function () { + eventHandler = new ClientLoginEventHandler(); + packetMessage = imock(); + device = imock(); + }); + + it('should define the name', function () { + expect(eventHandler.forName).to.be.equal('CLIENT_ONLINE_REQ'); + }); + + describe('#handle()', function () { + it('should respond when it has device', async function () { + when(packetMessage.device).thenReturn(device); + + await eventHandler.handle(instance(packetMessage)); + + verify(packetMessage.respond('CLIENT_ONLINE_RSP', deepEqual({ result: 0 }))).once(); + }); + + it('should respond when it does not has device', async function () { + const payload = new Payload({ + opcode: OPCode.fromName('CLIENT_ONLINE_REQ'), + data: { deviceSerialNumber: '1234567890', unk1: true, unk2: 1 }, + }); + const packet = new Packet({ ...givenSomePacketProps(), payload }); + + when(packetMessage.device).thenReturn(undefined); + when(packetMessage.packet).thenReturn(packet); + + await eventHandler.handle(instance(packetMessage)); + + verify( + packetMessage.respond( + 'CLIENT_ONLINE_RSP', + deepEqual({ result: 12002, reason: 'Device not registered(devsn: 1234567890)' }), + ), + ).once(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/packet-event-handlers/device-battery-update.event-handler.test.ts b/packages/adapter-tcp/src/packet-event-handlers/device-battery-update.event-handler.test.ts new file mode 100644 index 00000000..c212e2da --- /dev/null +++ b/packages/adapter-tcp/src/packet-event-handlers/device-battery-update.event-handler.test.ts @@ -0,0 +1,49 @@ +import { DeviceBattery } from '@agnoc/domain'; +import { OPCode, Packet, Payload } from '@agnoc/transport-tcp'; +import { givenSomePacketProps } from '@agnoc/transport-tcp/test-support'; +import { anything, deepEqual, imock, instance, verify, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { DeviceBatteryUpdateEventHandler } from './device-battery-update.event-handler'; +import type { DeviceBatteryMapper } from '../mappers/device-battery.mapper'; +import type { PacketMessage } from '../packet.message'; +import type { Device } from '@agnoc/domain'; + +describe('DeviceBatteryUpdateEventHandler', function () { + let deviceBatteryMapper: DeviceBatteryMapper; + let eventHandler: DeviceBatteryUpdateEventHandler; + let packetMessage: PacketMessage<'PUSH_DEVICE_BATTERY_INFO_REQ'>; + let device: Device; + + beforeEach(function () { + deviceBatteryMapper = imock(); + eventHandler = new DeviceBatteryUpdateEventHandler(instance(deviceBatteryMapper)); + packetMessage = imock(); + device = imock(); + }); + + it('should define the name', function () { + expect(eventHandler.forName).to.be.equal('PUSH_DEVICE_BATTERY_INFO_REQ'); + }); + + describe('#handle()', function () { + it('should update the device battery', async function () { + const deviceBattery = new DeviceBattery(5); + const payload = new Payload({ + opcode: OPCode.fromName('PUSH_DEVICE_BATTERY_INFO_REQ'), + data: { battery: { level: 1 } }, + }); + const packet = new Packet({ ...givenSomePacketProps(), payload }); + + when(deviceBatteryMapper.toDomain(anything())).thenReturn(deviceBattery); + when(packetMessage.packet).thenReturn(packet); + when(packetMessage.device).thenReturn(instance(device)); + + await eventHandler.handle(instance(packetMessage)); + + verify(packetMessage.assertDevice()).once(); + verify(deviceBatteryMapper.toDomain(1)).once(); + verify(device.updateBattery(deviceBattery)).once(); + verify(packetMessage.respond('PUSH_DEVICE_BATTERY_INFO_RSP', deepEqual({ result: 0 }))).once(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/packet-event-handlers/device-battery-update.event-handler.ts b/packages/adapter-tcp/src/packet-event-handlers/device-battery-update.event-handler.ts index 8f35f416..7252c2b4 100644 --- a/packages/adapter-tcp/src/packet-event-handlers/device-battery-update.event-handler.ts +++ b/packages/adapter-tcp/src/packet-event-handlers/device-battery-update.event-handler.ts @@ -1,4 +1,3 @@ -import { DomainException } from '@agnoc/toolkit'; import type { DeviceBatteryMapper } from '../mappers/device-battery.mapper'; import type { PacketEventHandler } from '../packet.event-handler'; import type { PacketMessage } from '../packet.message'; @@ -9,9 +8,7 @@ export class DeviceBatteryUpdateEventHandler implements PacketEventHandler { constructor(private readonly deviceBatteryMapper: DeviceBatteryMapper) {} async handle(message: PacketMessage<'PUSH_DEVICE_BATTERY_INFO_REQ'>): Promise { - if (!message.device) { - throw new DomainException('Device not found'); - } + message.assertDevice(); const data = message.packet.payload.data; diff --git a/packages/adapter-tcp/src/packet-event-handlers/device-settings-update.event-handler.ts b/packages/adapter-tcp/src/packet-event-handlers/device-settings-update.event-handler.ts index 92c03ae9..aa92aeb7 100644 --- a/packages/adapter-tcp/src/packet-event-handlers/device-settings-update.event-handler.ts +++ b/packages/adapter-tcp/src/packet-event-handlers/device-settings-update.event-handler.ts @@ -1,13 +1,13 @@ import { DeviceSetting, DeviceSettings, DeviceTime, QuietHoursSetting } from '@agnoc/domain'; import { DomainException } from '@agnoc/toolkit'; -import type { DeviceVoiceMapper } from '../mappers/device-voice.mapper'; +import type { VoiceSettingMapper } from '../mappers/voice-setting.mapper'; import type { PacketEventHandler } from '../packet.event-handler'; import type { PacketMessage } from '../packet.message'; export class DeviceSettingsUpdateEventHandler implements PacketEventHandler { readonly forName = 'PUSH_DEVICE_AGENT_SETTING_REQ'; - constructor(private readonly deviceVoiceMapper: DeviceVoiceMapper) {} + constructor(private readonly deviceVoiceMapper: VoiceSettingMapper) {} async handle(message: PacketMessage<'PUSH_DEVICE_AGENT_SETTING_REQ'>): Promise { if (!message.device) { diff --git a/packages/adapter-tcp/src/packet-event-publisher.service.test.ts b/packages/adapter-tcp/src/packet-event-publisher.service.test.ts new file mode 100644 index 00000000..59f9c43f --- /dev/null +++ b/packages/adapter-tcp/src/packet-event-publisher.service.test.ts @@ -0,0 +1,51 @@ +import { DomainException } from '@agnoc/toolkit'; +import { Packet } from '@agnoc/transport-tcp'; +import { givenSomePacketProps } from '@agnoc/transport-tcp/test-support'; +import { imock, instance, anything, verify, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { PacketEventPublisherService } from './packet-event-publisher.service'; +import { PacketMessage } from './packet.message'; +import type { PacketConnection } from './aggregate-roots/packet-connection.aggregate-root'; +import type { PacketEventBus } from './packet.event-bus'; + +describe('PacketEventPublisherService', function () { + let packetEventBus: PacketEventBus; + let packetConnection: PacketConnection; + let service: PacketEventPublisherService; + + beforeEach(function () { + packetEventBus = imock(); + packetConnection = imock(); + service = new PacketEventPublisherService(instance(packetEventBus)); + }); + + describe('#publishPacketMessage()', function () { + it('should emit packets through the packet event bus when has handlers for the packet', async function () { + const packet = new Packet(givenSomePacketProps()); + const packetMessage = new PacketMessage(instance(packetConnection), packet); + + when(packetEventBus.listenerCount(anything())).thenReturn(1); + + await service.publishPacketMessage(packetMessage); + + verify(packetEventBus.listenerCount(packet.payload.opcode.name)).once(); + verify(packetEventBus.emit(packet.sequence.toString(), packetMessage)).once(); + verify(packetEventBus.emit(packet.payload.opcode.name, packetMessage)).once(); + }); + + it('should throw an error when there is no handlers for the packet', async function () { + const packet = new Packet(givenSomePacketProps()); + const packetMessage = new PacketMessage(instance(packetConnection), packet); + + when(packetEventBus.listenerCount(anything())).thenReturn(0); + + await expect(service.publishPacketMessage(packetMessage)).to.be.rejectedWith( + DomainException, + `No event handler found for packet event 'DEVICE_GETTIME_RSP'`, + ); + + verify(packetEventBus.listenerCount(packet.payload.opcode.name)).once(); + verify(packetEventBus.emit(anything(), anything())).never(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/packet-event-publisher.service.ts b/packages/adapter-tcp/src/packet-event-publisher.service.ts new file mode 100644 index 00000000..01b19079 --- /dev/null +++ b/packages/adapter-tcp/src/packet-event-publisher.service.ts @@ -0,0 +1,31 @@ +import { DomainException } from '@agnoc/toolkit'; +import type { PacketEventBus, PacketEventBusEvents } from './packet.event-bus'; +import type { PacketMessage } from './packet.message'; +import type { PayloadDataName } from '@agnoc/transport-tcp'; + +export class PacketEventPublisherService { + constructor(private readonly packetEventBus: PacketEventBus) {} + + async publishPacketMessage(packetMessage: PacketMessage): Promise { + const name = packetMessage.packet.payload.opcode.name as PayloadDataName; + const sequence = packetMessage.packet.sequence.toString(); + + this.checkForPacketEventHandler(name); + + // Emit the packet event by the sequence string. + // This is used to wait for a response from a packet. + await this.packetEventBus.emit(sequence, packetMessage as PacketEventBusEvents[PayloadDataName]); + + // Emit the packet event by the opcode name. + await this.packetEventBus.emit(name, packetMessage as PacketEventBusEvents[PayloadDataName]); + } + + private checkForPacketEventHandler(event: PayloadDataName) { + const count = this.packetEventBus.listenerCount(event); + + // Throw an error if there is no event handler for the packet event. + if (count === 0) { + throw new DomainException(`No event handler found for packet event '${event}'`); + } + } +} diff --git a/packages/adapter-tcp/src/packet-server.connection-handler.test.ts b/packages/adapter-tcp/src/packet-server.connection-handler.test.ts new file mode 100644 index 00000000..90c3402e --- /dev/null +++ b/packages/adapter-tcp/src/packet-server.connection-handler.test.ts @@ -0,0 +1,152 @@ +import { anything, capture, defer, imock, instance, verify, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { PackerServerConnectionHandler } from './packet-server.connection-handler'; +import { PacketMessage } from './packet.message'; +import type { PacketConnection } from './aggregate-roots/packet-connection.aggregate-root'; +import type { ConnectionDeviceUpdaterService } from './connection-device-updater.service'; +import type { PacketConnectionFactory } from './factories/connection.factory'; +import type { PacketEventPublisherService } from './packet-event-publisher.service'; +import type { ConnectionRepository } from '@agnoc/domain'; +import type { Packet, PacketServer, PacketSocket } from '@agnoc/transport-tcp'; + +describe('PackerServerConnectionHandler', function () { + let connectionRepository: ConnectionRepository; + let packetConnectionFactory: PacketConnectionFactory; + let updateConnectionDeviceService: ConnectionDeviceUpdaterService; + let packetEventPublisherService: PacketEventPublisherService; + let handler: PackerServerConnectionHandler; + let packetServer: PacketServer; + let packetSocket: PacketSocket; + let packetConnection: PacketConnection; + let packet: Packet; + + beforeEach(function () { + connectionRepository = imock(); + packetConnectionFactory = imock(); + updateConnectionDeviceService = imock(); + packetEventPublisherService = imock(); + handler = new PackerServerConnectionHandler( + instance(connectionRepository), + instance(packetConnectionFactory), + instance(updateConnectionDeviceService), + instance(packetEventPublisherService), + ); + packetServer = imock(); + packetSocket = imock(); + packetConnection = imock(); + packet = imock(); + }); + + describe('#addServers', function () { + it('should register a server and listen for connections', function () { + const onClose = defer(); + + when(packetServer.once(anything())).thenResolve(onClose); + + handler.addServers(instance(packetServer)); + + verify(packetServer.on('connection', anything())).once(); + verify(packetServer.once('close')).once(); + }); + + it('should handle connections', async function () { + const onClose = defer(); + + when(packetServer.once(anything())).thenResolve(onClose); + + handler.addServers(instance(packetServer)); + + when(packetConnectionFactory.create(anything())).thenReturn(instance(packetConnection)); + when(packetConnection.socket).thenReturn(instance(packetSocket)); + + const [, onConnection] = capture<'connection', (socket: PacketSocket) => Promise>(packetServer.on).first(); + + await onConnection(instance(packetSocket)); + + verify(connectionRepository.saveOne(instance(packetConnection))).once(); + verify(packetSocket.on('data', anything())).once(); + verify(packetSocket.once('close', anything())).once(); + }); + + it('should close connections on server close', async function () { + const onClose = defer(); + + when(packetServer.once(anything())).thenResolve(onClose); + + handler.addServers(instance(packetServer)); + + when(packetConnectionFactory.create(anything())).thenReturn(instance(packetConnection)); + when(packetConnection.socket).thenReturn(instance(packetSocket)); + + const [, onConnection] = capture<'connection', (socket: PacketSocket) => Promise>(packetServer.on).first(); + + await onConnection(instance(packetSocket)); + await onClose.resolve(undefined); + + verify(packetServer.off('connection', onConnection)).once(); + verify(packetConnection.close()).once(); + }); + + it('should server close without connections', async function () { + const onClose = defer(); + + when(packetServer.once(anything())).thenResolve(onClose); + + handler.addServers(instance(packetServer)); + + await onClose.resolve(undefined); + + verify(packetConnection.close()).never(); + }); + + it('should handle connection data', async function () { + const onClose = defer(); + + when(packetServer.once(anything())).thenResolve(onClose); + + handler.addServers(instance(packetServer)); + + when(packetConnectionFactory.create(anything())).thenReturn(instance(packetConnection)); + when(packetConnection.socket).thenReturn(instance(packetSocket)); + + const [, onConnection] = capture<'connection', (socket: PacketSocket) => Promise>(packetServer.on).first(); + + await onConnection(instance(packetSocket)); + + const [, onData] = capture<'data', (packet: Packet) => Promise>(packetSocket.on).first(); + + await onData(instance(packet)); + + verify(updateConnectionDeviceService.updateFromPacket(instance(packet), instance(packetConnection))).once(); + + const [packetMessage] = capture(packetEventPublisherService.publishPacketMessage).first(); + + expect(packetMessage).to.be.instanceOf(PacketMessage); + expect(packetMessage.packet).to.equal(instance(packet)); + expect(packetMessage.connection).to.equal(instance(packetConnection)); + }); + + it('should handle connection close', async function () { + const onClose = defer(); + + when(packetServer.once(anything())).thenResolve(onClose); + + handler.addServers(instance(packetServer)); + + when(packetConnectionFactory.create(anything())).thenReturn(instance(packetConnection)); + when(packetConnection.socket).thenReturn(instance(packetSocket)); + + const [, onConnection] = capture<'connection', (socket: PacketSocket) => Promise>(packetServer.on).first(); + + await onConnection(instance(packetSocket)); + + const [, onData] = capture<'data', (packet: Packet) => Promise>(packetSocket.on).first(); + const [, onConnectionClose] = capture<'close', () => Promise>(packetSocket.once).first(); + + await onConnectionClose(); + + verify(packetSocket.off('data', onData)).once(); + verify(connectionRepository.deleteOne(instance(packetConnection))).once(); + }); + }); +}); diff --git a/packages/adapter-tcp/src/packet-server.connection-handler.ts b/packages/adapter-tcp/src/packet-server.connection-handler.ts index 72ed16b4..e5439e18 100644 --- a/packages/adapter-tcp/src/packet-server.connection-handler.ts +++ b/packages/adapter-tcp/src/packet-server.connection-handler.ts @@ -1,19 +1,20 @@ -import { DomainException, ID } from '@agnoc/toolkit'; +import { ID } from '@agnoc/toolkit'; import { PacketMessage } from './packet.message'; import type { PacketConnection } from './aggregate-roots/packet-connection.aggregate-root'; +import type { ConnectionDeviceUpdaterService } from './connection-device-updater.service'; import type { PacketConnectionFactory } from './factories/connection.factory'; -import type { PacketEventBus, PacketEventBusEvents } from './packet.event-bus'; -import type { DeviceRepository, Device, Connection, ConnectionRepository } from '@agnoc/domain'; -import type { PacketServer, Packet, PayloadDataName } from '@agnoc/transport-tcp'; +import type { PacketEventPublisherService } from './packet-event-publisher.service'; +import type { ConnectionRepository } from '@agnoc/domain'; +import type { PacketServer, Packet, PacketSocket } from '@agnoc/transport-tcp'; export class PackerServerConnectionHandler { private readonly servers = new Map>(); constructor( - private readonly packetEventBus: PacketEventBus, - private readonly deviceRepository: DeviceRepository, private readonly connectionRepository: ConnectionRepository, private readonly packetConnectionFactory: PacketConnectionFactory, + private readonly updateConnectionDeviceService: ConnectionDeviceUpdaterService, + private readonly packetEventPublisherService: PacketEventPublisherService, ) {} addServers(...servers: PacketServer[]): void { @@ -24,75 +25,51 @@ export class PackerServerConnectionHandler { } private addListeners(server: PacketServer) { - server.on('connection', (socket) => { - const connection = this.packetConnectionFactory.create({ id: ID.generate(), socket }); + const onConnection = (socket: PacketSocket) => this.handleServerConnection(server, socket); - this.servers.get(server)?.add(connection); + server.on('connection', onConnection); - connection.socket.on('data', async (packet: Packet) => { - const packetMessage = new PacketMessage(connection, packet); + void server.once('close').then(() => { + server.off('connection', onConnection); - // Update the device on the connection if the device id has changed. - await this.updateConnectionDevice(packet, connection); - - // Send the packet message to the packet event bus. - await this.emitPacketEvent(packetMessage); - }); - - connection.socket.on('close', () => { - this.servers.get(server)?.delete(connection); - }); - }); - - server.on('close', async () => { - const connections = this.servers.get(server); - - if (connections) { - await Promise.all([...connections].map((connection) => connection.close())); - - this.servers.delete(server); - } + return this.handleServerClose(server); }); } - private async emitPacketEvent(message: PacketMessage) { - const name = message.packet.payload.opcode.name as PayloadDataName; - const sequence = message.packet.sequence.toString(); - - this.checkForPacketEventHandler(name); + private async handleServerClose(server: PacketServer) { + const connections = this.servers.get(server) as Set; - // Emit the packet event by the sequence string. - // This is used to wait for a response from a packet. - await this.packetEventBus.emit(sequence, message as PacketEventBusEvents[PayloadDataName]); + this.servers.delete(server); - // Emit the packet event by the opcode name. - await this.packetEventBus.emit(name, message as PacketEventBusEvents[PayloadDataName]); + await Promise.all([...connections].map((connection) => connection.close())); } - private checkForPacketEventHandler(event: PayloadDataName) { - const count = this.packetEventBus.listenerCount(event); + private async handleServerConnection(server: PacketServer, socket: PacketSocket) { + const connection = this.packetConnectionFactory.create({ id: ID.generate(), socket }); - // Throw an error if there is no event handler for the packet event. - if (count === 0) { - throw new DomainException(`No event handler found for packet event '${event}'`); - } - } + this.servers.get(server)?.add(connection); - private async updateConnectionDevice(packet: Packet, connection: Connection) { - if (!packet.deviceId.equals(connection.device?.id)) { - const device = await this.findDeviceById(packet.deviceId); + // Should this be done before or after registering the listeners? + await this.connectionRepository.saveOne(connection); - connection.setDevice(device); + const onData = (packet: Packet) => this.handleConnectionData(connection, packet); + const onClose = () => { + connection.socket.off('data', onData); + this.servers.get(server)?.delete(connection); + return this.connectionRepository.deleteOne(connection); + }; - await this.connectionRepository.saveOne(connection); - } + connection.socket.on('data', onData); + connection.socket.once('close', onClose); } - private async findDeviceById(id: ID): Promise { - if (id.value === 0) { - return undefined; - } + private async handleConnectionData(connection: PacketConnection, packet: Packet) { + const packetMessage = new PacketMessage(connection, packet); + + // Update the device on the connection if the device id has changed. + await this.updateConnectionDeviceService.updateFromPacket(packet, connection); - return this.deviceRepository.findOneById(id); + // Send the packet message to the packet event bus. + await this.packetEventPublisherService.publishPacketMessage(packetMessage); } } diff --git a/packages/adapter-tcp/src/packet.message.test.ts b/packages/adapter-tcp/src/packet.message.test.ts new file mode 100644 index 00000000..0e17bbd9 --- /dev/null +++ b/packages/adapter-tcp/src/packet.message.test.ts @@ -0,0 +1,119 @@ +import { Device } from '@agnoc/domain'; +import { givenSomeDeviceProps } from '@agnoc/domain/test-support'; +import { DomainException } from '@agnoc/toolkit'; +import { OPCode, Packet, Payload } from '@agnoc/transport-tcp'; +import { givenSomePacketProps, givenSomePayloadProps } from '@agnoc/transport-tcp/test-support'; +import { anything, imock, instance, verify, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { PacketMessage } from './packet.message'; +import type { PacketConnection } from './aggregate-roots/packet-connection.aggregate-root'; + +describe('PacketMessage', function () { + let packetConnection: PacketConnection; + let packet: Packet; + let packetMessage: PacketMessage; + + beforeEach(function () { + packetConnection = imock(); + packet = imock(); + packetMessage = new PacketMessage(instance(packetConnection), instance(packet)); + }); + + it('should be created', function () { + const device = new Device(givenSomeDeviceProps()); + + when(packetConnection.device).thenReturn(device); + + expect(packetMessage).to.exist; + expect(packetMessage.device).to.be.equal(device); + }); + + describe('#respond()', function () { + it('should respond to the connection', async function () { + const data = { result: 0, body: { deviceTime: 1 } }; + + when(packetConnection.respond(anything(), anything(), anything())).thenResolve(undefined); + + await packetMessage.respond('DEVICE_GETTIME_RSP', data); + + verify(packetConnection.respond('DEVICE_GETTIME_RSP', data, instance(packet))).once(); + }); + }); + + describe('#respondAndWait()', function () { + it('should respond to the connection and wait for the response', async function () { + const data = { result: 0, body: { deviceTime: 1 } }; + const anotherPacketMessage = new PacketMessage(instance(packetConnection), instance(packet)); + + when(packetConnection.respondAndWait(anything(), anything(), anything())).thenResolve(anotherPacketMessage); + + const ret = await packetMessage.respondAndWait('DEVICE_GETTIME_RSP', data); + + expect(ret).to.be.equal(anotherPacketMessage); + + verify(packetConnection.respondAndWait('DEVICE_GETTIME_RSP', data, instance(packet))).once(); + }); + }); + + describe('#hasPayloadName()', function () { + it('should return true when the payload name is the same', function () { + const opcode = OPCode.fromName('DEVICE_GETTIME_RSP'); + const payload = new Payload({ ...givenSomePayloadProps(), opcode }); + const packet = new Packet({ ...givenSomePacketProps(), payload }); + const packetMessage = new PacketMessage(instance(packetConnection), packet); + + expect(packetMessage.hasPayloadName('DEVICE_GETTIME_RSP')).to.be.true; + }); + + it('should return false when the payload name is not the same', function () { + const opcode = OPCode.fromName('DEVICE_GETTIME_RSP'); + const payload = new Payload({ ...givenSomePayloadProps(), opcode }); + const packet = new Packet({ ...givenSomePacketProps(), payload }); + const packetMessage = new PacketMessage(instance(packetConnection), packet); + + expect(packetMessage.hasPayloadName('DEVICE_GETTIME_REQ')).to.be.false; + }); + }); + + describe('#assertPayloadName()', function () { + it('should throw an error when the payload name is not the same', function () { + const opcode = OPCode.fromName('DEVICE_GETTIME_RSP'); + const payload = new Payload({ ...givenSomePayloadProps(), opcode }); + const packet = new Packet({ ...givenSomePacketProps(), payload }); + const packetMessage = new PacketMessage(instance(packetConnection), packet); + + expect(() => packetMessage.assertPayloadName('DEVICE_GETTIME_REQ')).to.throw( + DomainException, + `Unexpected packet with payload name 'DEVICE_GETTIME_RSP', expecting 'DEVICE_GETTIME_REQ'`, + ); + }); + + it('should not throw an error when the payload name is the same', function () { + const opcode = OPCode.fromName('DEVICE_GETTIME_RSP'); + const payload = new Payload({ ...givenSomePayloadProps(), opcode }); + const packet = new Packet({ ...givenSomePacketProps(), payload }); + const packetMessage = new PacketMessage(instance(packetConnection), packet); + + expect(() => packetMessage.assertPayloadName('DEVICE_GETTIME_RSP')).to.not.throw(DomainException); + }); + }); + + describe('#assertDevice()', function () { + it('should throw an error when the connection does not has a device set', function () { + when(packetConnection.device).thenReturn(undefined); + + expect(() => packetMessage.assertDevice()).to.throw( + DomainException, + 'Connection does not have a reference to a device', + ); + }); + + it('should not throw an error when the connection has a device set', function () { + const device = new Device(givenSomeDeviceProps()); + + when(packetConnection.device).thenReturn(device); + + expect(() => packetMessage.assertDevice()).to.not.throw(DomainException); + }); + }); +}); diff --git a/packages/adapter-tcp/src/packet.message.ts b/packages/adapter-tcp/src/packet.message.ts index 8bdda9bf..e7b3a033 100644 --- a/packages/adapter-tcp/src/packet.message.ts +++ b/packages/adapter-tcp/src/packet.message.ts @@ -1,3 +1,4 @@ +import { DomainException } from '@agnoc/toolkit'; import type { PacketConnection } from './aggregate-roots/packet-connection.aggregate-root'; import type { Device } from '@agnoc/domain'; import type { Packet, PayloadDataFrom, PayloadDataName } from '@agnoc/transport-tcp'; @@ -16,4 +17,22 @@ export class PacketMessage { respondAndWait(name: Name, object: PayloadDataFrom): Promise { return this.connection.respondAndWait(name, object, this.packet); } + + hasPayloadName(name: Name): this is PacketMessage { + return this.packet.payload.opcode.value === (name as string); + } + + assertPayloadName(name: Name): asserts this is PacketMessage { + if (!this.hasPayloadName(name)) { + throw new DomainException( + `Unexpected packet with payload name '${this.packet.payload.opcode.value}', expecting '${name}'`, + ); + } + } + + assertDevice(): asserts this is PacketMessage & { device: Device } { + if (!this.device) { + throw new DomainException('Connection does not have a reference to a device'); + } + } } diff --git a/packages/adapter-tcp/src/tcp.server.test.ts b/packages/adapter-tcp/src/tcp.server.test.ts index 5ef401c8..1b230d81 100644 --- a/packages/adapter-tcp/src/tcp.server.test.ts +++ b/packages/adapter-tcp/src/tcp.server.test.ts @@ -29,7 +29,12 @@ describe('TCPServer', function () { }); it('should listen and close servers with custom ports', async function () { - await tcpAdapter.listen({ host: '127.0.0.1', ports: { cmd: 0, map: 0, ntp: 0 } }); + await tcpAdapter.listen({ ports: { cmd: 0, map: 0, ntp: 0 } }); + await tcpAdapter.close(); + }); + + it('should listen and close servers with custom host', async function () { + await tcpAdapter.listen({ host: '127.0.0.1' }); await tcpAdapter.close(); }); }); diff --git a/packages/adapter-tcp/src/tcp.server.ts b/packages/adapter-tcp/src/tcp.server.ts index ae68c898..e1792bd9 100644 --- a/packages/adapter-tcp/src/tcp.server.ts +++ b/packages/adapter-tcp/src/tcp.server.ts @@ -8,19 +8,21 @@ import { PayloadDataParserService, PacketFactory, } from '@agnoc/transport-tcp'; -import { LocateDeviceEventHandler } from './command-handlers/locate-device.event-handler'; +import { LocateDeviceCommandHandler } from './command-handlers/locate-device.command-handler'; +import { ConnectionDeviceUpdaterService } from './connection-device-updater.service'; import { LockDeviceWhenDeviceIsConnectedEventHandler } from './domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler'; import { QueryDeviceInfoWhenDeviceIsLockedEventHandler } from './domain-event-handlers/query-device-info-when-device-is-locked-event-handler.event-handler'; -import { SetDeviceAsConnectedWhenConnectionDeviceAddedDomainEventHandler } from './domain-event-handlers/set-device-connected-when-connection-device-changed.domain-event'; +import { SetDeviceAsConnectedWhenConnectionDeviceAddedEventHandler } from './domain-event-handlers/set-device-connected-when-connection-device-changed.event-handler'; import { PacketConnectionFactory } from './factories/connection.factory'; import { DeviceBatteryMapper } from './mappers/device-battery.mapper'; import { DeviceErrorMapper } from './mappers/device-error.mapper'; import { DeviceFanSpeedMapper } from './mappers/device-fan-speed.mapper'; import { DeviceModeMapper } from './mappers/device-mode.mapper'; import { DeviceStateMapper } from './mappers/device-state.mapper'; -import { DeviceVoiceMapper } from './mappers/device-voice.mapper'; import { DeviceWaterLevelMapper } from './mappers/device-water-level.mapper'; +import { VoiceSettingMapper } from './mappers/voice-setting.mapper'; import { NTPServerConnectionHandler } from './ntp-server.connection-handler'; +import { PacketConnectionFinderService } from './packet-connection-finder.service'; import { ClientHeartbeatEventHandler } from './packet-event-handlers/client-heartbeat.event-handler'; import { ClientLoginEventHandler } from './packet-event-handlers/client-login.event-handler'; import { DeviceBatteryUpdateEventHandler } from './packet-event-handlers/device-battery-update.event-handler'; @@ -41,6 +43,7 @@ import { DeviceTimeUpdateEventHandler } from './packet-event-handlers/device-tim import { DeviceUpgradeInfoEventHandler } from './packet-event-handlers/device-upgrade-info.event-handler'; import { DeviceVersionUpdateEventHandler } from './packet-event-handlers/device-version-update.event-handler'; import { DeviceWlanUpdateEventHandler } from './packet-event-handlers/device-wlan-update.event-handler'; +import { PacketEventPublisherService } from './packet-event-publisher.service'; import { PackerServerConnectionHandler } from './packet-server.connection-handler'; import { PacketEventBus } from './packet.event-bus'; import type { CommandsOrQueries, ConnectionRepository, DeviceRepository } from '@agnoc/domain'; @@ -71,7 +74,7 @@ export class TCPServer implements Server { // Mappers const deviceFanSpeedMapper = new DeviceFanSpeedMapper(); const deviceWaterLevelMapper = new DeviceWaterLevelMapper(); - const deviceVoiceMapper = new DeviceVoiceMapper(); + const deviceVoiceMapper = new VoiceSettingMapper(); const deviceStateMapper = new DeviceStateMapper(); const deviceModeMapper = new DeviceModeMapper(); const deviceErrorMapper = new DeviceErrorMapper(); @@ -83,11 +86,14 @@ export class TCPServer implements Server { // Connection const packetConnectionFactory = new PacketConnectionFactory(packetEventBus, packetFactory); + const connectionDeviceUpdaterService = new ConnectionDeviceUpdaterService(connectionRepository, deviceRepository); + const packetEventPublisherService = new PacketEventPublisherService(packetEventBus); + const packetConnectionFinderService = new PacketConnectionFinderService(connectionRepository); const connectionManager = new PackerServerConnectionHandler( - packetEventBus, - this.deviceRepository, this.connectionRepository, packetConnectionFactory, + connectionDeviceUpdaterService, + packetEventPublisherService, ); connectionManager.addServers(this.cmdServer, this.mapServer); @@ -136,13 +142,13 @@ export class TCPServer implements Server { // Domain event handlers this.domainEventHandlerRegistry.register( - new LockDeviceWhenDeviceIsConnectedEventHandler(connectionRepository), - new QueryDeviceInfoWhenDeviceIsLockedEventHandler(connectionRepository), - new SetDeviceAsConnectedWhenConnectionDeviceAddedDomainEventHandler(connectionRepository, deviceRepository), + new LockDeviceWhenDeviceIsConnectedEventHandler(packetConnectionFinderService), + new QueryDeviceInfoWhenDeviceIsLockedEventHandler(packetConnectionFinderService), + new SetDeviceAsConnectedWhenConnectionDeviceAddedEventHandler(connectionRepository, deviceRepository), ); // Command event handlers - this.commandQueryHandlerRegistry.register(new LocateDeviceEventHandler(connectionRepository)); + this.commandQueryHandlerRegistry.register(new LocateDeviceCommandHandler(packetConnectionFinderService)); } async listen(options: TCPAdapterListenOptions = listenDefaultOptions): Promise { diff --git a/packages/core/src/query-handlers/find-device.query-handler.test.ts b/packages/core/src/query-handlers/find-device.query-handler.test.ts new file mode 100644 index 00000000..5b27052c --- /dev/null +++ b/packages/core/src/query-handlers/find-device.query-handler.test.ts @@ -0,0 +1,48 @@ +import { Device, FindDeviceQuery } from '@agnoc/domain'; +import { givenSomeDeviceProps } from '@agnoc/domain/test-support'; +import { ID } from '@agnoc/toolkit'; +import { anything, imock, instance, verify, when } from '@johanblumenberg/ts-mockito'; +import { expect } from 'chai'; +import { FindDeviceQueryHandler } from './find-device.query-handler'; +import type { DeviceRepository } from '@agnoc/domain'; + +describe('FindDeviceQueryHandler', function () { + let deviceRepository: DeviceRepository; + let queryHandler: FindDeviceQueryHandler; + + beforeEach(function () { + deviceRepository = imock(); + queryHandler = new FindDeviceQueryHandler(instance(deviceRepository)); + }); + + it('should define the name', function () { + expect(queryHandler.forName).to.be.equal('FindDeviceQuery'); + }); + + describe('#handle()', function () { + it('should find a device', async function () { + const deviceId = new ID(1); + const device = new Device(givenSomeDeviceProps()); + const query = new FindDeviceQuery({ deviceId }); + + when(deviceRepository.findOneById(anything())).thenResolve(device); + + const result = await queryHandler.handle(query); + + expect(result).to.be.deep.equal({ device }); + + verify(deviceRepository.findOneById(deviceId)).once(); + }); + + it("throw an error when 'device' is not found", async function () { + const deviceId = new ID(1); + const query = new FindDeviceQuery({ deviceId }); + + when(deviceRepository.findOneById(anything())).thenResolve(undefined); + + await expect(queryHandler.handle(query)).to.be.rejectedWith(`Unable to find a device with id ${deviceId.value}`); + + verify(deviceRepository.findOneById(deviceId)).once(); + }); + }); +}); diff --git a/packages/domain/src/queries/find-device-query.test.ts b/packages/domain/src/queries/find-device-query.test.ts new file mode 100644 index 00000000..6c127fe4 --- /dev/null +++ b/packages/domain/src/queries/find-device-query.test.ts @@ -0,0 +1,60 @@ +import { ArgumentInvalidException, ArgumentNotProvidedException, ID, Query } from '@agnoc/toolkit'; +import { expect } from 'chai'; +import { Device } from '../aggregate-roots/device.aggregate-root'; +import { givenSomeDeviceProps } from '../test-support'; +import { FindDeviceQuery } from './find-device.query'; +import type { FindDeviceQueryInput, FindDeviceQueryOutput } from './find-device.query'; + +describe('FindDeviceQuery', function () { + it('should be created', function () { + const input = givenAFindDeviceQueryInput(); + const query = new FindDeviceQuery(input); + + expect(query).to.be.instanceOf(Query); + expect(query.deviceId).to.be.equal(input.deviceId); + }); + + it("should throw an error when 'deviceId' is not provided", function () { + // @ts-expect-error - missing property + expect(() => new FindDeviceQuery({ ...givenAFindDeviceQueryInput(), deviceId: undefined })).to.throw( + ArgumentNotProvidedException, + `Property 'deviceId' for FindDeviceQuery not provided`, + ); + }); + + it("should throw an error when 'deviceId' is not an ID", function () { + // @ts-expect-error - invalid property + expect(() => new FindDeviceQuery({ ...givenAFindDeviceQueryInput(), deviceId: 'foo' })).to.throw( + ArgumentInvalidException, + `Value 'foo' for property 'deviceId' of FindDeviceQuery is not an instance of ID`, + ); + }); + + it("should throw an error when 'device' is not provided", function () { + const query = new FindDeviceQuery(givenAFindDeviceQueryInput()); + + // @ts-expect-error - missing property + expect(() => query.validateOutput({ ...givenAFindDeviceQueryOutput(), device: undefined })).to.throw( + ArgumentNotProvidedException, + `Property 'device' for FindDeviceQuery not provided`, + ); + }); + + it("should throw an error when 'device' is not a Device", function () { + const query = new FindDeviceQuery(givenAFindDeviceQueryInput()); + + // @ts-expect-error - missing property + expect(() => query.validateOutput({ ...givenAFindDeviceQueryOutput(), device: 'foo' })).to.throw( + ArgumentInvalidException, + `Value 'foo' for property 'device' of FindDeviceQuery is not an instance of Device`, + ); + }); +}); + +function givenAFindDeviceQueryInput(): FindDeviceQueryInput { + return { deviceId: ID.generate() }; +} + +function givenAFindDeviceQueryOutput(): FindDeviceQueryOutput { + return { device: new Device(givenSomeDeviceProps()) }; +} diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index 593b76bc..427e0669 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -10,10 +10,10 @@ "./typescript": "./typescript.js" }, "dependencies": { - "@typescript-eslint/eslint-plugin": "^5.53.0", - "@typescript-eslint/parser": "^5.53.0", - "eslint": "^8.35.0", - "eslint-config-prettier": "^8.6.0", + "@typescript-eslint/eslint-plugin": "^5.56.0", + "@typescript-eslint/parser": "^5.56.0", + "eslint": "^8.36.0", + "eslint-config-prettier": "^8.8.0", "eslint-import-resolver-typescript": "^3.5.3", "eslint-plugin-chai-friendly": "^0.7.2", "eslint-plugin-import": "^2.27.5", diff --git a/packages/schemas-tcp/src/index.proto b/packages/schemas-tcp/src/index.proto index dfa8a226..e5bff3de 100644 --- a/packages/schemas-tcp/src/index.proto +++ b/packages/schemas-tcp/src/index.proto @@ -295,7 +295,7 @@ message DEVICE_ORDERLIST_SETTING_REQ { required uint32 planId = 2; required uint32 cleanMode = 3; required uint32 windPower = 4; - required uint32 waterLevel = 5; + optional uint32 waterLevel = 5; required bool twiceClean = 6; } diff --git a/packages/transport-tcp/src/packet.socket.test.ts b/packages/transport-tcp/src/packet.socket.test.ts index 295953a8..e93f0a62 100644 --- a/packages/transport-tcp/src/packet.socket.test.ts +++ b/packages/transport-tcp/src/packet.socket.test.ts @@ -1,4 +1,4 @@ -import { Server } from 'net'; +import { Server, Socket } from 'net'; import { Duplex } from 'stream'; import { setTimeout } from 'timers/promises'; import { DomainException } from '@agnoc/toolkit'; @@ -209,7 +209,7 @@ describe('PacketSocket', function () { server.listen(0); }); - it('should wrap an existing socket', function (done) { + it('should wrap an existing connected socket', function (done) { const buffer = givenAPacketBuffer(); const packet = new Packet(givenSomePacketProps()); @@ -223,6 +223,14 @@ describe('PacketSocket', function () { server.once('connection', (socket) => { const packetSocketServer = new PacketSocket(instance(packetMapper), socket); + expect(packetSocket.localAddress).to.be.a('string'); + expect(packetSocket.localPort).to.be.a('number'); + expect(packetSocket.remoteAddress).to.be.a('string'); + expect(packetSocket.remotePort).to.be.a('number'); + expect(packetSocket.toString()).to.be.not.equal('unknown:0::unknown:0'); + expect(packetSocket.connecting).to.be.false; + expect(packetSocket.connected).to.be.true; + void packetSocketServer.end(packet); }); @@ -234,6 +242,18 @@ describe('PacketSocket', function () { server.listen(0); }); + it('should wrap an existing socket', function () { + packetSocket = new PacketSocket(instance(packetMapper), new Socket()); + + expect(packetSocket.localAddress).to.be.undefined; + expect(packetSocket.localPort).to.be.undefined; + expect(packetSocket.remoteAddress).to.be.undefined; + expect(packetSocket.remotePort).to.be.undefined; + expect(packetSocket.toString()).to.be.equal('unknown:0::unknown:0'); + expect(packetSocket.connecting).to.be.false; + expect(packetSocket.connected).to.be.false; + }); + describe('#connect()', function () { it('should connect to a server by options', function (done) { server.once('listening', () => { diff --git a/packages/transport-tcp/src/packet.socket.ts b/packages/transport-tcp/src/packet.socket.ts index 4b614626..f82bc4e2 100644 --- a/packages/transport-tcp/src/packet.socket.ts +++ b/packages/transport-tcp/src/packet.socket.ts @@ -148,7 +148,7 @@ export class PacketSocket extends Duplex { /** Returns whether the socket is connected. */ get connected(): boolean { - return this.socket?.readyState === 'open'; + return !this.socket?.pending && this.socket?.readyState === 'open'; } /** Returns an string representation of the socket addresses. */ @@ -279,6 +279,7 @@ export declare interface PacketSocket extends Duplex { emit(event: U, ...args: Parameters): boolean; on(event: U, listener: PacketSocketEvents[U]): this; once(event: U, listener: PacketSocketEvents[U]): this; + off(event: U, listener: PacketSocketEvents[U]): this; write(packet: Packet, encoding: BufferEncoding, cb: WriteCallback): boolean; write(packet: Packet, cb: WriteCallback): boolean; write(packet: Packet): Promise; diff --git a/yarn.lock b/yarn.lock index 195f1164..1da752eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -191,14 +191,19 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" -"@commitlint/cli@^17.4.4": - version "17.4.4" - resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-17.4.4.tgz#36df08bfa31dbb9a2b6b1d7187a31e578f001a06" - integrity sha512-HwKlD7CPVMVGTAeFZylVNy14Vm5POVY0WxPkZr7EXLC/os0LH/obs6z4HRvJtH/nHCMYBvUBQhGwnufKfTjd5g== +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@commitlint/cli@^17.5.0": + version "17.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-17.5.0.tgz#045bf46fc38bb4246da30b462d8db66f48c28f9a" + integrity sha512-yNW3+M7UM1ioK28LKTrryIVB5qGpXlEv8+rJQiWPMZNayy9/1XR5+lL8qBTNlgopYtZWWnIm5RETcAN29ZTL/A== dependencies: "@commitlint/format" "^17.4.4" "@commitlint/lint" "^17.4.4" - "@commitlint/load" "^17.4.4" + "@commitlint/load" "^17.5.0" "@commitlint/read" "^17.4.4" "@commitlint/types" "^17.4.4" execa "^5.0.0" @@ -265,10 +270,10 @@ "@commitlint/rules" "^17.4.4" "@commitlint/types" "^17.4.4" -"@commitlint/load@>6.1.1", "@commitlint/load@^17.4.4": - version "17.4.4" - resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-17.4.4.tgz#13fcb553572f265339801cde6dd10ee5eea07f5e" - integrity sha512-z6uFIQ7wfKX5FGBe1AkOF4l/ShOQsaa1ml/nLMkbW7R/xF8galGS7Zh0yHvzVp/srtfS0brC+0bUfQfmpMPFVQ== +"@commitlint/load@>6.1.1", "@commitlint/load@^17.5.0": + version "17.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-17.5.0.tgz#be45dbbb50aaf5eb7e8e940e1e0d6171d1426bab" + integrity sha512-l+4W8Sx4CD5rYFsrhHH8HP01/8jEP7kKf33Xlx2Uk2out/UKoKPYMOIRcDH5ppT8UXLMV+x6Wm5osdRKKgaD1Q== dependencies: "@commitlint/config-validator" "^17.4.4" "@commitlint/execute-rule" "^17.4.0" @@ -283,7 +288,7 @@ lodash.uniq "^4.5.0" resolve-from "^5.0.0" ts-node "^10.8.1" - typescript "^4.6.4" + typescript "^4.6.4 || ^5.0.0" "@commitlint/message@^17.4.2": version "17.4.2" @@ -359,14 +364,26 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@eslint/eslintrc@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.0.tgz#943309d8697c52fc82c076e90c1c74fbbe69dbff" - integrity sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A== +"@eslint-community/eslint-utils@^4.2.0": + version "4.3.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz#a556790523a351b4e47e9d385f47265eaaf9780a" + integrity sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.1.tgz#087cb8d9d757bb22e9c9946c9c0c2bf8806830f1" + integrity sha512-BISJ6ZE4xQsuL/FmsyRaiffpq977bMlsKfGHTQrOGFErfByxIe6iZTxPf/00Zon9b9a7iUykfQwejN3s2ZW/Bw== + +"@eslint/eslintrc@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.1.tgz#7888fe7ec8f21bc26d646dbd2c11cd776e21192d" + integrity sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.4.0" + espree "^9.5.0" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -374,10 +391,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.35.0": - version "8.35.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.35.0.tgz#b7569632b0b788a0ca0e438235154e45d42813a7" - integrity sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw== +"@eslint/js@8.36.0": + version "8.36.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe" + integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg== "@gar/promisify@^1.1.3": version "1.1.3" @@ -436,6 +453,13 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== +"@jest/schemas@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" + integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== + dependencies: + "@sinclair/typebox" "^0.25.16" + "@johanblumenberg/ts-mockito@^1.0.35": version "1.0.35" resolved "https://registry.yarnpkg.com/@johanblumenberg/ts-mockito/-/ts-mockito-1.0.35.tgz#045fde7d479c2d0ed0156ea8e5ffb6eddbbd14b8" @@ -498,21 +522,21 @@ dependencies: lodash "^4.17.21" -"@lerna/child-process@6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-6.5.1.tgz#da9161ba00e8d67fa7241a709703e5cc5e4a5e5e" - integrity sha512-QfyleXSD9slh4qM54wDaqKVPvtUH1NJMgsFc9BabqSHO1Ttpandv1EAvTCN9Lu73RbCX3LJpn+BfJmnjHbjCyw== +"@lerna/child-process@6.6.0": + version "6.6.0" + resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-6.6.0.tgz#6bd2effce7a2dd3a06b67db1c2cb6cc999859519" + integrity sha512-Y1elVHYKBLvdseKu74ud+pWqQi0I81AeWBKLRs0ehnD2EZsmy/f5ILkRcNU9aUp4GPF1TMUPAq2/+0By97gb1g== dependencies: chalk "^4.1.0" execa "^5.0.0" strong-log-transformer "^2.1.0" -"@lerna/create@6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-6.5.1.tgz#326b5d26c247bfc9e2d8728aa1f69419840cec8c" - integrity sha512-ejERJnfA36jEuKrfM+94feLiyf2/hF2NoG923N0rE4rsmvRFPr1XLVPvAKleXW+Gdi/t1p410lJ7NKaLRMYCYw== +"@lerna/create@6.6.0": + version "6.6.0" + resolved "https://registry.yarnpkg.com/@lerna/create/-/create-6.6.0.tgz#7cec9d9c16c00e7d6359e76e75a12d2dc3ac987b" + integrity sha512-F1Q4bB9QzePSnIPd2ZY6a+3l/aZiYYmN1J0ednr8O+xMOyZsumX29c4XvnS7rgovz4aFqi+XdXiL35vmvrSfjA== dependencies: - "@lerna/child-process" "6.5.1" + "@lerna/child-process" "6.6.0" dedent "^0.7.0" fs-extra "^9.1.0" init-package-json "^3.0.2" @@ -526,6 +550,75 @@ validate-npm-package-name "^4.0.0" yargs-parser "20.2.4" +"@lerna/legacy-package-management@6.6.0": + version "6.6.0" + resolved "https://registry.yarnpkg.com/@lerna/legacy-package-management/-/legacy-package-management-6.6.0.tgz#099a918cf1df82aa47ae21172db25643c5b0e4f5" + integrity sha512-vGkQv7nuZNhjs1+Arm1m+CKyBblig4oSv/PakyNnqTnRNryIgdXqYFn8DGGkUsA3qXLlouY41Sz5xEY/7hjNEA== + dependencies: + "@npmcli/arborist" "6.2.3" + "@npmcli/run-script" "4.1.7" + "@nrwl/devkit" ">=15.5.2 < 16" + "@octokit/rest" "19.0.3" + byte-size "7.0.0" + chalk "4.1.0" + clone-deep "4.0.1" + cmd-shim "5.0.0" + columnify "1.6.0" + config-chain "1.1.12" + conventional-changelog-core "4.2.4" + conventional-recommended-bump "6.1.0" + cosmiconfig "7.0.0" + dedent "0.7.0" + dot-prop "6.0.1" + execa "5.0.0" + file-url "3.0.0" + find-up "5.0.0" + fs-extra "9.1.0" + get-port "5.1.1" + get-stream "6.0.0" + git-url-parse "13.1.0" + glob-parent "5.1.2" + globby "11.1.0" + graceful-fs "4.2.10" + has-unicode "2.0.1" + inquirer "8.2.4" + is-ci "2.0.0" + is-stream "2.0.0" + libnpmpublish "6.0.4" + load-json-file "6.2.0" + make-dir "3.1.0" + minimatch "3.0.5" + multimatch "5.0.0" + node-fetch "2.6.7" + npm-package-arg "8.1.1" + npm-packlist "5.1.1" + npm-registry-fetch "14.0.3" + npmlog "6.0.2" + p-map "4.0.0" + p-map-series "2.1.0" + p-queue "6.6.2" + p-waterfall "2.1.1" + pacote "13.6.2" + path-exists "4.0.0" + pify "5.0.0" + pretty-format "29.4.3" + read-cmd-shim "3.0.0" + read-package-json "5.0.1" + resolve-from "5.0.0" + semver "7.3.8" + signal-exit "3.0.7" + slash "3.0.0" + ssri "9.0.1" + strong-log-transformer "2.1.0" + tar "6.1.11" + temp-dir "1.0.0" + tempy "1.0.0" + upath "2.0.1" + uuid "8.3.2" + write-file-atomic "4.0.1" + write-pkg "4.0.0" + yargs "16.2.0" + "@microsoft/tsdoc-config@0.16.2": version "0.16.2" resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz#b786bb4ead00d54f53839a458ce626c8548d3adf" @@ -562,44 +655,43 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@npmcli/arborist@5.3.0": - version "5.3.0" - resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-5.3.0.tgz#321d9424677bfc08569e98a5ac445ee781f32053" - integrity sha512-+rZ9zgL1lnbl8Xbb1NQdMjveOMwj4lIYfcDtyJHHi5x4X8jtR6m8SXooJMZy5vmFVZ8w7A2Bnd/oX9eTuU8w5A== +"@npmcli/arborist@6.2.3": + version "6.2.3" + resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-6.2.3.tgz#31f8aed2588341864d3811151d929c01308f8e71" + integrity sha512-lpGOC2ilSJXcc2zfW9QtukcCTcMbl3fVI0z4wvFB2AFIl0C+Q6Wv7ccrpdrQa8rvJ1ZVuc6qkX7HVTyKlzGqKA== dependencies: "@isaacs/string-locale-compare" "^1.1.0" - "@npmcli/installed-package-contents" "^1.0.7" - "@npmcli/map-workspaces" "^2.0.3" - "@npmcli/metavuln-calculator" "^3.0.1" - "@npmcli/move-file" "^2.0.0" - "@npmcli/name-from-folder" "^1.0.1" - "@npmcli/node-gyp" "^2.0.0" - "@npmcli/package-json" "^2.0.0" - "@npmcli/run-script" "^4.1.3" - bin-links "^3.0.0" - cacache "^16.0.6" + "@npmcli/fs" "^3.1.0" + "@npmcli/installed-package-contents" "^2.0.0" + "@npmcli/map-workspaces" "^3.0.2" + "@npmcli/metavuln-calculator" "^5.0.0" + "@npmcli/name-from-folder" "^2.0.0" + "@npmcli/node-gyp" "^3.0.0" + "@npmcli/package-json" "^3.0.0" + "@npmcli/query" "^3.0.0" + "@npmcli/run-script" "^6.0.0" + bin-links "^4.0.1" + cacache "^17.0.4" common-ancestor-path "^1.0.1" - json-parse-even-better-errors "^2.3.1" + hosted-git-info "^6.1.1" + json-parse-even-better-errors "^3.0.0" json-stringify-nice "^1.1.4" - mkdirp "^1.0.4" - mkdirp-infer-owner "^2.0.0" - nopt "^5.0.0" - npm-install-checks "^5.0.0" - npm-package-arg "^9.0.0" - npm-pick-manifest "^7.0.0" - npm-registry-fetch "^13.0.0" - npmlog "^6.0.2" - pacote "^13.6.1" - parse-conflict-json "^2.0.1" - proc-log "^2.0.0" + minimatch "^6.1.6" + nopt "^7.0.0" + npm-install-checks "^6.0.0" + npm-package-arg "^10.1.0" + npm-pick-manifest "^8.0.1" + npm-registry-fetch "^14.0.3" + npmlog "^7.0.1" + pacote "^15.0.8" + parse-conflict-json "^3.0.0" + proc-log "^3.0.0" promise-all-reject-late "^1.0.0" promise-call-limit "^1.0.1" - read-package-json-fast "^2.0.2" - readdir-scoped-modules "^1.1.0" - rimraf "^3.0.2" + read-package-json-fast "^3.0.2" semver "^7.3.7" - ssri "^9.0.0" - treeverse "^2.0.0" + ssri "^10.0.1" + treeverse "^3.0.0" walk-up-path "^1.0.0" "@npmcli/fs@^2.1.0": @@ -655,32 +747,32 @@ npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" -"@npmcli/installed-package-contents@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-2.0.1.tgz#3cad3141c95613426820128757a3549bef1b346b" - integrity sha512-GIykAFdOVK31Q1/zAtT5MbxqQL2vyl9mvFJv+OGu01zxbhL3p0xc8gJjdNGX1mWmUT43aEKVO2L6V/2j4TOsAA== +"@npmcli/installed-package-contents@^2.0.0", "@npmcli/installed-package-contents@^2.0.1": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz#bfd817eccd9e8df200919e73f57f9e3d9e4f9e33" + integrity sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ== dependencies: npm-bundled "^3.0.0" npm-normalize-package-bin "^3.0.0" -"@npmcli/map-workspaces@^2.0.3": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-2.0.4.tgz#9e5e8ab655215a262aefabf139782b894e0504fc" - integrity sha512-bMo0aAfwhVwqoVM5UzX1DJnlvVvzDCHae821jv48L1EsrYwfOZChlqWYXEtto/+BkBXetPbEWgau++/brh4oVg== +"@npmcli/map-workspaces@^3.0.2": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-3.0.3.tgz#476944b63cd1f65bf83c6fdc7f4ca7be56906b1f" + integrity sha512-HlCvFuTzw4UNoKyZdqiNrln+qMF71QJkxy2dsusV8QQdoa89e2TF4dATCzBxbl4zzRzdDoWWyP5ADVrNAH9cRQ== dependencies: - "@npmcli/name-from-folder" "^1.0.1" - glob "^8.0.1" - minimatch "^5.0.1" - read-package-json-fast "^2.0.3" + "@npmcli/name-from-folder" "^2.0.0" + glob "^9.3.1" + minimatch "^7.4.2" + read-package-json-fast "^3.0.0" -"@npmcli/metavuln-calculator@^3.0.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-3.1.1.tgz#9359bd72b400f8353f6a28a25c8457b562602622" - integrity sha512-n69ygIaqAedecLeVH3KnO39M6ZHiJ2dEv5A7DGvcqCB8q17BGUgW8QaanIkbWUo2aYGZqJaOORTLAlIvKjNDKA== +"@npmcli/metavuln-calculator@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-5.0.0.tgz#917c3be49ebed0b424b07f38060b929127e4c499" + integrity sha512-BBFQx4M12wiEuVwCgtX/Depx0B/+NHMwDWOlXT41/Pdy5W/1Fenk+hibUlMSrFWwASbX+fY90UbILAEIYH02/A== dependencies: - cacache "^16.0.0" - json-parse-even-better-errors "^2.3.1" - pacote "^13.0.3" + cacache "^17.0.0" + json-parse-even-better-errors "^3.0.0" + pacote "^15.0.0" semver "^7.3.5" "@npmcli/move-file@^2.0.0": @@ -691,10 +783,10 @@ mkdirp "^1.0.4" rimraf "^3.0.2" -"@npmcli/name-from-folder@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz#77ecd0a4fcb772ba6fe927e2e2e155fbec2e6b1a" - integrity sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA== +"@npmcli/name-from-folder@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz#c44d3a7c6d5c184bb6036f4d5995eee298945815" + integrity sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg== "@npmcli/node-gyp@^2.0.0": version "2.0.0" @@ -706,12 +798,12 @@ resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz#101b2d0490ef1aa20ed460e4c0813f0db560545a" integrity sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA== -"@npmcli/package-json@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-2.0.0.tgz#3bbcf4677e21055adbe673d9f08c9f9cde942e4a" - integrity sha512-42jnZ6yl16GzjWSH7vtrmWyJDGVa/LXPdpN2rcUWolFjc9ON2N3uz0qdBbQACfmhuJZ2lbKYtmK5qx68ZPLHMA== +"@npmcli/package-json@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-3.0.0.tgz#c9219a197e1be8dbf43c4ef8767a72277c0533b6" + integrity sha512-NnuPuM97xfiCpbTEJYtEuKz6CFbpUHtaT0+5via5pQeI25omvQDFbp1GcGJ/c4zvL/WX0qbde6YiLgfZbWFgvg== dependencies: - json-parse-even-better-errors "^2.3.1" + json-parse-even-better-errors "^3.0.0" "@npmcli/promise-spawn@^3.0.0": version "3.0.0" @@ -727,7 +819,14 @@ dependencies: which "^3.0.0" -"@npmcli/run-script@4.1.7": +"@npmcli/query@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@npmcli/query/-/query-3.0.0.tgz#51a0dfb85811e04f244171f164b6bc83b36113a7" + integrity sha512-MFNDSJNgsLZIEBVZ0Q9w9K7o07j5N4o4yjtdz2uEpuCZlXGMuPENiRaFYk0vRqAA64qVuUQwC05g27fRtfUgnA== + dependencies: + postcss-selector-parser "^6.0.10" + +"@npmcli/run-script@4.1.7", "@npmcli/run-script@^4.1.0": version "4.1.7" resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-4.1.7.tgz#b1a2f57568eb738e45e9ea3123fb054b400a86f7" integrity sha512-WXr/MyM4tpKA4BotB81NccGAv8B48lNH0gRoILucbcAhTQXLCoi6HflMV3KdXubIqvP9SuLsFn68Z7r4jl+ppw== @@ -738,17 +837,6 @@ read-package-json-fast "^2.0.3" which "^2.0.2" -"@npmcli/run-script@^4.1.0", "@npmcli/run-script@^4.1.3": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-4.2.1.tgz#c07c5c71bc1c70a5f2a06b0d4da976641609b946" - integrity sha512-7dqywvVudPSrRCW5nTHpHgeWnbBtz8cFkOuKrecm6ih+oO9ciydhWt6OF7HlqupRRmB8Q/gECVdB9LMfToJbRg== - dependencies: - "@npmcli/node-gyp" "^2.0.0" - "@npmcli/promise-spawn" "^3.0.0" - node-gyp "^9.0.0" - read-package-json-fast "^2.0.3" - which "^2.0.2" - "@npmcli/run-script@^6.0.0": version "6.0.0" resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-6.0.0.tgz#f89e322c729e26ae29db6cc8cc76559074aac208" @@ -842,7 +930,7 @@ debug "^4.1.1" semver "^7.3.8" -"@oclif/config@1.18.6": +"@oclif/config@1.18.6", "@oclif/config@^1.18.2": version "1.18.6" resolved "https://registry.yarnpkg.com/@oclif/config/-/config-1.18.6.tgz#37367026b3110a2f04875509b1920a8ee4489f21" integrity sha512-OWhCpdu4QqggOPX1YPZ4XVmLLRX+lhGjXV6RNA7sogOwLqlEmSslnN/lhR5dkhcWZbKWBQH29YCrB3LDPRu/IA== @@ -854,18 +942,6 @@ is-wsl "^2.1.1" tslib "^2.3.1" -"@oclif/config@^1.18.2": - version "1.18.8" - resolved "https://registry.yarnpkg.com/@oclif/config/-/config-1.18.8.tgz#efaccbd0381f90a98fa69c9131e14c5a91fc0659" - integrity sha512-FetS52+emaZQui0roFSdbBP8ddBkIezEoH2NcjLJRjqkMGdE9Z1V+jsISVqTYXk2KJ1gAI0CHDXFjJlNBYbJBg== - dependencies: - "@oclif/errors" "^1.3.6" - "@oclif/parser" "^3.8.10" - debug "^4.3.4" - globby "^11.1.0" - is-wsl "^2.1.1" - tslib "^2.5.0" - "@oclif/errors@1.3.6", "@oclif/errors@^1.3.5", "@oclif/errors@^1.3.6": version "1.3.6" resolved "https://registry.yarnpkg.com/@oclif/errors/-/errors-1.3.6.tgz#e8fe1fc12346cb77c4f274e26891964f5175f75d" @@ -1137,6 +1213,11 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@sinclair/typebox@^0.25.16": + version "0.25.24" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" + integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== + "@sindresorhus/is@^5.2.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.3.0.tgz#0ec9264cf54a527671d990eb874e030b55b70dcc" @@ -1258,10 +1339,10 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== -"@types/node@*", "@types/node@>=13.7.0", "@types/node@^18.14.2": - version "18.14.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.2.tgz#c076ed1d7b6095078ad3cf21dfeea951842778b1" - integrity sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA== +"@types/node@*", "@types/node@>=13.7.0", "@types/node@^18.15.5": + version "18.15.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.5.tgz#3af577099a99c61479149b716183e70b5239324a" + integrity sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew== "@types/node@^10.0.0": version "10.17.60" @@ -1283,88 +1364,88 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== -"@typescript-eslint/eslint-plugin@^5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.53.0.tgz#24b8b4a952f3c615fe070e3c461dd852b5056734" - integrity sha512-alFpFWNucPLdUOySmXCJpzr6HKC3bu7XooShWM+3w/EL6J2HIoB2PFxpLnq4JauWVk6DiVeNKzQlFEaE+X9sGw== +"@typescript-eslint/eslint-plugin@^5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.56.0.tgz#e4fbb4d6dd8dab3e733485c1a44a02189ae75364" + integrity sha512-ZNW37Ccl3oMZkzxrYDUX4o7cnuPgU+YrcaYXzsRtLB16I1FR5SHMqga3zGsaSliZADCWo2v8qHWqAYIj8nWCCg== dependencies: - "@typescript-eslint/scope-manager" "5.53.0" - "@typescript-eslint/type-utils" "5.53.0" - "@typescript-eslint/utils" "5.53.0" + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.56.0" + "@typescript-eslint/type-utils" "5.56.0" + "@typescript-eslint/utils" "5.56.0" debug "^4.3.4" grapheme-splitter "^1.0.4" ignore "^5.2.0" natural-compare-lite "^1.4.0" - regexpp "^3.2.0" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.53.0.tgz#a1f2b9ae73b83181098747e96683f1b249ecab52" - integrity sha512-MKBw9i0DLYlmdOb3Oq/526+al20AJZpANdT6Ct9ffxcV8nKCHz63t/S0IhlTFNsBIHJv+GY5SFJ0XfqVeydQrQ== +"@typescript-eslint/parser@^5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.56.0.tgz#42eafb44b639ef1dbd54a3dbe628c446ca753ea6" + integrity sha512-sn1OZmBxUsgxMmR8a8U5QM/Wl+tyqlH//jTqCg8daTAmhAk26L2PFhcqPLlYBhYUJMZJK276qLXlHN3a83o2cg== dependencies: - "@typescript-eslint/scope-manager" "5.53.0" - "@typescript-eslint/types" "5.53.0" - "@typescript-eslint/typescript-estree" "5.53.0" + "@typescript-eslint/scope-manager" "5.56.0" + "@typescript-eslint/types" "5.56.0" + "@typescript-eslint/typescript-estree" "5.56.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.53.0.tgz#42b54f280e33c82939275a42649701024f3fafef" - integrity sha512-Opy3dqNsp/9kBBeCPhkCNR7fmdSQqA+47r21hr9a14Bx0xnkElEQmhoHga+VoaoQ6uDHjDKmQPIYcUcKJifS7w== +"@typescript-eslint/scope-manager@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.56.0.tgz#62b4055088903b5254fa20403010e1c16d6ab725" + integrity sha512-jGYKyt+iBakD0SA5Ww8vFqGpoV2asSjwt60Gl6YcO8ksQ8s2HlUEyHBMSa38bdLopYqGf7EYQMUIGdT/Luw+sw== dependencies: - "@typescript-eslint/types" "5.53.0" - "@typescript-eslint/visitor-keys" "5.53.0" + "@typescript-eslint/types" "5.56.0" + "@typescript-eslint/visitor-keys" "5.56.0" -"@typescript-eslint/type-utils@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.53.0.tgz#41665449935ba9b4e6a1ba6e2a3f4b2c31d6cf97" - integrity sha512-HO2hh0fmtqNLzTAme/KnND5uFNwbsdYhCZghK2SoxGp3Ifn2emv+hi0PBUjzzSh0dstUIFqOj3bp0AwQlK4OWw== +"@typescript-eslint/type-utils@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.56.0.tgz#e6f004a072f09c42e263dc50e98c70b41a509685" + integrity sha512-8WxgOgJjWRy6m4xg9KoSHPzBNZeQbGlQOH7l2QEhQID/+YseaFxg5J/DLwWSsi9Axj4e/cCiKx7PVzOq38tY4A== dependencies: - "@typescript-eslint/typescript-estree" "5.53.0" - "@typescript-eslint/utils" "5.53.0" + "@typescript-eslint/typescript-estree" "5.56.0" + "@typescript-eslint/utils" "5.56.0" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.53.0.tgz#f79eca62b97e518ee124086a21a24f3be267026f" - integrity sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A== +"@typescript-eslint/types@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.56.0.tgz#b03f0bfd6fa2afff4e67c5795930aff398cbd834" + integrity sha512-JyAzbTJcIyhuUhogmiu+t79AkdnqgPUEsxMTMc/dCZczGMJQh1MK2wgrju++yMN6AWroVAy2jxyPcPr3SWCq5w== -"@typescript-eslint/typescript-estree@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.53.0.tgz#bc651dc28cf18ab248ecd18a4c886c744aebd690" - integrity sha512-eKmipH7QyScpHSkhbptBBYh9v8FxtngLquq292YTEQ1pxVs39yFBlLC1xeIZcPPz1RWGqb7YgERJRGkjw8ZV7w== +"@typescript-eslint/typescript-estree@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.56.0.tgz#48342aa2344649a03321e74cab9ccecb9af086c3" + integrity sha512-41CH/GncsLXOJi0jb74SnC7jVPWeVJ0pxQj8bOjH1h2O26jXN3YHKDT1ejkVz5YeTEQPeLCCRY0U2r68tfNOcg== dependencies: - "@typescript-eslint/types" "5.53.0" - "@typescript-eslint/visitor-keys" "5.53.0" + "@typescript-eslint/types" "5.56.0" + "@typescript-eslint/visitor-keys" "5.56.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.53.0.tgz#e55eaad9d6fffa120575ffaa530c7e802f13bce8" - integrity sha512-VUOOtPv27UNWLxFwQK/8+7kvxVC+hPHNsJjzlJyotlaHjLSIgOCKj9I0DBUjwOOA64qjBwx5afAPjksqOxMO0g== +"@typescript-eslint/utils@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.56.0.tgz#db64705409b9a15546053fb4deb2888b37df1f41" + integrity sha512-XhZDVdLnUJNtbzaJeDSCIYaM+Tgr59gZGbFuELgF7m0IY03PlciidS7UQNKLE0+WpUTn1GlycEr6Ivb/afjbhA== dependencies: + "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.53.0" - "@typescript-eslint/types" "5.53.0" - "@typescript-eslint/typescript-estree" "5.53.0" + "@typescript-eslint/scope-manager" "5.56.0" + "@typescript-eslint/types" "5.56.0" + "@typescript-eslint/typescript-estree" "5.56.0" eslint-scope "^5.1.1" - eslint-utils "^3.0.0" semver "^7.3.7" -"@typescript-eslint/visitor-keys@5.53.0": - version "5.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.53.0.tgz#8a5126623937cdd909c30d8fa72f79fa56cc1a9f" - integrity sha512-JqNLnX3leaHFZEN0gCh81sIvgrp/2GOACZNgO4+Tkf64u51kTpAyWFOY8XHx8XuXr3N2C9zgPPHtcpMg6z1g0w== +"@typescript-eslint/visitor-keys@5.56.0": + version "5.56.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.56.0.tgz#f19eb297d972417eb13cb69b35b3213e13cc214f" + integrity sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q== dependencies: - "@typescript-eslint/types" "5.53.0" + "@typescript-eslint/types" "5.56.0" eslint-visitor-keys "^3.3.0" "@yarnpkg/lockfile@^1.1.0": @@ -1395,11 +1476,23 @@ JSONStream@^1.0.4: jsonparse "^1.2.0" through ">=2.2.7 <3" -abbrev@1, abbrev@^1.0.0: +abbrev@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -1471,16 +1564,11 @@ ansi-align@^3.0.1: dependencies: string-width "^4.1.0" -ansi-colors@4.1.1: +ansi-colors@4.1.1, ansi-colors@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-colors@^4.1.1: - version "4.1.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" - integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== - ansi-escapes@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" @@ -1522,6 +1610,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0, ansi-styles@^4.2.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + ansi-styles@^6.0.0, ansi-styles@^6.1.0: version "6.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" @@ -1565,6 +1658,14 @@ are-we-there-yet@^3.0.0: delegates "^1.0.0" readable-stream "^3.6.0" +are-we-there-yet@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-4.0.0.tgz#3ff397dc14f08b52dd8b2a64d3cee154ab8760d2" + integrity sha512-nSXlV+u3vtVjRgihdTzbfWYzxPWGo424zPgQbHD0ZqIla3jqYAewDcvee0Ua2hjS5IfTAmjGlx1Jf0PKwjZDEw== + dependencies: + delegates "^1.0.0" + readable-stream "^4.1.0" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -1648,11 +1749,6 @@ arrify@^2.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -asap@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== - assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -1707,17 +1803,15 @@ before-after-hook@^2.2.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== -bin-links@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-3.0.3.tgz#3842711ef3db2cd9f16a5f404a996a12db355a6e" - integrity sha512-zKdnMPWEdh4F5INR07/eBrodC7QrF5JKvqskjz/ZZRXg5YSAZIbn8zGhbhUrElzHBZ2fvEQdOU59RHcTG3GiwA== +bin-links@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-4.0.1.tgz#afeb0549e642f61ff889b58ea2f8dca78fb9d8d3" + integrity sha512-bmFEM39CyX336ZGGRsGPlc6jZHriIoHacOQcTt72MktIjpPhZoP4te2jOyUXF3BLILmJ8aNLncoPVeIIFlrDeA== dependencies: - cmd-shim "^5.0.0" - mkdirp-infer-owner "^2.0.0" - npm-normalize-package-bin "^2.0.0" - read-cmd-shim "^3.0.0" - rimraf "^3.0.0" - write-file-atomic "^4.0.0" + cmd-shim "^6.0.0" + npm-normalize-package-bin "^3.0.0" + read-cmd-shim "^4.0.0" + write-file-atomic "^5.0.0" binary-extensions@^2.0.0: version "2.2.0" @@ -1802,6 +1896,14 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" @@ -1819,7 +1921,7 @@ byte-size@7.0.0: resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.0.tgz#36528cd1ca87d39bd9abd51f5715dc93b6ceb032" integrity sha512-NNiBxKgxybMBtWdmvx7ZITJi4ZG+CYUgwOSZTfqB1qogkRHrhbQE/R2r5Fh94X+InN5MCYz6SvB/ejHMj/HbsQ== -cacache@^16.0.0, cacache@^16.0.6, cacache@^16.1.0: +cacache@^16.0.0, cacache@^16.1.0: version "16.1.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.3.tgz#a02b9f34ecfaf9a78c9f4bc16fceb94d5d67a38e" integrity sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ== @@ -1843,14 +1945,14 @@ cacache@^16.0.0, cacache@^16.0.6, cacache@^16.1.0: tar "^6.1.11" unique-filename "^2.0.0" -cacache@^17.0.0: - version "17.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.0.4.tgz#5023ed892ba8843e3b7361c26d0ada37e146290c" - integrity sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA== +cacache@^17.0.0, cacache@^17.0.4: + version "17.0.5" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.0.5.tgz#6dbec26c11f1f6a2b558bc11ed3316577c339ebc" + integrity sha512-Y/PRQevNSsjAPWykl9aeGz8Pr+OI6BYM9fYDNMvOkuUiG9IhG4LEmaYrZZZvioMUEQ+cBCxT0v8wrnCURccyKA== dependencies: "@npmcli/fs" "^3.1.0" fs-minipass "^3.0.0" - glob "^8.0.1" + glob "^9.3.1" lru-cache "^7.7.1" minipass "^4.0.0" minipass-collect "^1.0.2" @@ -1980,6 +2082,11 @@ chalk@4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@5.2.0, chalk@^5.0.1, chalk@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" + integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== + chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1997,11 +2104,6 @@ chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^5.0.1, chalk@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" - integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== - chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -2073,22 +2175,19 @@ cli-progress@^3.4.0: dependencies: string-width "^4.2.3" -cli-spinners@2.6.1: +cli-spinners@2.6.1, cli-spinners@^2.5.0: version "2.6.1" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== -cli-spinners@^2.5.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" - integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== - -cli-table@^0.3.11: - version "0.3.11" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.11.tgz#ac69cdecbe81dccdba4889b9a18b7da312a9d3ee" - integrity sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ== +cli-table3@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" + integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== dependencies: - colors "1.0.3" + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" cli-truncate@^2.1.0: version "2.1.0" @@ -2184,13 +2283,18 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -cmd-shim@5.0.0, cmd-shim@^5.0.0: +cmd-shim@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-5.0.0.tgz#8d0aaa1a6b0708630694c4dbde070ed94c707724" integrity sha512-qkCtZ59BidfEwHltnJwkyVZn+XQojdAySM1D1gSeh11Z4pW1Kpolkyo53L5noc0nrxmIvyFwTmJRo4xs7FFLPw== dependencies: mkdirp-infer-owner "^2.0.0" +cmd-shim@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-6.0.1.tgz#a65878080548e1dca760b3aea1e21ed05194da9d" + integrity sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -2225,11 +2329,6 @@ colorette@^2.0.19: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw== - columnify@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" @@ -2328,7 +2427,7 @@ concat-stream@^2.0.0: readable-stream "^3.0.2" typedarray "^0.0.6" -config-chain@1.1.12: +config-chain@1.1.12, config-chain@^1.1.11: version "1.1.12" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== @@ -2336,14 +2435,6 @@ config-chain@1.1.12: ini "^1.3.4" proto-list "~1.2.1" -config-chain@^1.1.11: - version "1.1.13" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" - integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - configstore@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/configstore/-/configstore-6.0.0.tgz#49eca2ebc80983f77e09394a1a56e0aca8235566" @@ -2360,7 +2451,7 @@ console-control-strings@^1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== -conventional-changelog-angular@5.0.12: +conventional-changelog-angular@5.0.12, conventional-changelog-angular@^5.0.11: version "5.0.12" resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz#c979b8b921cbfe26402eb3da5bbfda02d865a2b9" integrity sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw== @@ -2368,14 +2459,6 @@ conventional-changelog-angular@5.0.12: compare-func "^2.0.0" q "^1.5.1" -conventional-changelog-angular@^5.0.11: - version "5.0.13" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" - integrity sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA== - dependencies: - compare-func "^2.0.0" - q "^1.5.1" - conventional-changelog-conventionalcommits@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz#41bdce54eb65a848a4a3ffdca93e92fa22b64a86" @@ -2525,6 +2608,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + crypto-random-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-4.0.0.tgz#5a3cc53d7dd86183df5da0312816ceeeb5bb1fc2" @@ -2532,6 +2620,11 @@ crypto-random-string@^4.0.0: dependencies: type-fest "^1.0.1" +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + cz-conventional-changelog@3.3.0, cz-conventional-changelog@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz#9246947c90404149b3fe2cf7ee91acad3b7d22d2" @@ -2570,11 +2663,6 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debuglog@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" - integrity sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw== - decamelize-keys@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" @@ -2654,6 +2742,20 @@ define-properties@^1.1.3, define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +del@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" + integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg== + dependencies: + globby "^11.0.1" + graceful-fs "^4.2.4" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.2" + p-map "^4.0.0" + rimraf "^3.0.2" + slash "^3.0.0" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -2689,14 +2791,6 @@ detect-indent@^5.0.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" integrity sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g== -dezalgo@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" - integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig== - dependencies: - asap "^2.0.0" - wrappy "1" - diff@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" @@ -2946,10 +3040,10 @@ escodegen@^1.13.0: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@^8.6.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz#dec1d29ab728f4fa63061774e1672ac4e363d207" - integrity sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA== +eslint-config-prettier@^8.8.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" + integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== eslint-import-resolver-node@^0.3.7: version "0.3.7" @@ -3101,13 +3195,15 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8.35.0: - version "8.35.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.35.0.tgz#fffad7c7e326bae606f0e8f436a6158566d42323" - integrity sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw== +eslint@^8.36.0: + version "8.36.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.36.0.tgz#1bd72202200a5492f91803b113fb8a83b11285cf" + integrity sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw== dependencies: - "@eslint/eslintrc" "^2.0.0" - "@eslint/js" "8.35.0" + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.1" + "@eslint/js" "8.36.0" "@humanwhocodes/config-array" "^0.11.8" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -3118,9 +3214,8 @@ eslint@^8.35.0: doctrine "^3.0.0" escape-string-regexp "^4.0.0" eslint-scope "^7.1.1" - eslint-utils "^3.0.0" eslint-visitor-keys "^3.3.0" - espree "^9.4.0" + espree "^9.5.0" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -3142,15 +3237,14 @@ eslint@^8.35.0: minimatch "^3.1.2" natural-compare "^1.4.0" optionator "^0.9.1" - regexpp "^3.2.0" strip-ansi "^6.0.1" strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^9.0.0, espree@^9.4.0: - version "9.4.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" - integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== +espree@^9.0.0, espree@^9.5.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.0.tgz#3646d4e3f58907464edba852fa047e6a27bdf113" + integrity sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw== dependencies: acorn "^8.8.0" acorn-jsx "^5.3.2" @@ -3190,11 +3284,21 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +events@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + execa@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376" @@ -3225,14 +3329,14 @@ execa@^5.0.0, execa@^5.1.1: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -execa@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20" - integrity sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA== +execa@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43" + integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q== dependencies: cross-spawn "^7.0.3" get-stream "^6.0.1" - human-signals "^3.0.1" + human-signals "^4.3.0" is-stream "^3.0.0" merge-stream "^2.0.0" npm-run-path "^5.1.0" @@ -3329,6 +3433,11 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-url@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/file-url/-/file-url-3.0.0.tgz#247a586a746ce9f7a8ed05560290968afc262a77" + integrity sha512-g872QGsHexznxkIAdK8UiZRe7SkE6kvylShU4Nsj8NvfvZag7S0QuQ4IgvPDkk75HxgjIVDwycFTDAgIiO4nDA== + filelist@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" @@ -3558,6 +3667,20 @@ gauge@^4.0.3: strip-ansi "^6.0.1" wide-align "^1.1.5" +gauge@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-5.0.0.tgz#e270ca9d97dae84abf64e5277ef1ebddc7dd1e2f" + integrity sha512-0s5T5eciEG7Q3ugkxAkFtaDhrrhXsCRivA5y8C9WMHWuI8UlMOJg7+Iwf7Mccii+Dfs3H5jHepU0joPVyQU0Lw== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.3" + console-control-strings "^1.1.0" + has-unicode "^2.0.1" + signal-exit "^3.0.7" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.5" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -3740,6 +3863,16 @@ glob@^8.0.0, glob@^8.0.1: minimatch "^5.0.1" once "^1.3.0" +glob@^9.2.0, glob@^9.3.1: + version "9.3.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.2.tgz#8528522e003819e63d11c979b30896e0eaf52eda" + integrity sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA== + dependencies: + fs.realpath "^1.0.0" + minimatch "^7.4.1" + minipass "^4.2.4" + path-scurry "^1.6.1" + global-dirs@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" @@ -3798,7 +3931,7 @@ globalyzer@0.1.0: resolved "https://registry.yarnpkg.com/globalyzer/-/globalyzer-0.1.0.tgz#cb76da79555669a1519d5a8edf093afaa0bf1465" integrity sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q== -globby@11.1.0, globby@^11.0.4, globby@^11.1.0: +globby@11.1.0, globby@^11.0.1, globby@^11.0.4, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -3979,7 +4112,7 @@ hosted-git-info@^5.0.0, hosted-git-info@^5.1.0: dependencies: lru-cache "^7.5.1" -hosted-git-info@^6.0.0: +hosted-git-info@^6.0.0, hosted-git-info@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-6.1.1.tgz#629442c7889a69c05de604d52996b74fe6f26d58" integrity sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w== @@ -4026,10 +4159,10 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -human-signals@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5" - integrity sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ== +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== humanize-ms@^1.2.1: version "1.2.1" @@ -4062,7 +4195,7 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.13: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -4145,10 +4278,10 @@ ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -ini@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ini/-/ini-3.0.1.tgz#c76ec81007875bc44d544ff7a11a55d12294102d" - integrity sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ== +ini@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.0.0.tgz#35b4b0ba3bb9a3feb8c50dbf92fb1671efda88eb" + integrity sha512-t0ikzf5qkSFqRl1e6ejKBe+Tk2bsQd8ivEkcisyGXsku2t8NvXZ1Y3RRz5vxrDgOrTBOi13CvGsVoI5wVpd7xg== init-package-json@3.0.2, init-package-json@^3.0.2: version "3.0.2" @@ -4163,6 +4296,27 @@ init-package-json@3.0.2, init-package-json@^3.0.2: validate-npm-package-license "^3.0.4" validate-npm-package-name "^4.0.0" +inquirer@8.2.4: + version "8.2.4" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.4.tgz#ddbfe86ca2f67649a67daa6f1051c128f684f0b4" + integrity sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.5.5" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + wrap-ansi "^7.0.0" + inquirer@8.2.5, inquirer@^8.2.4: version "8.2.5" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8" @@ -4339,6 +4493,11 @@ is-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== +is-path-cwd@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + is-path-inside@^3.0.2, is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -4388,16 +4547,11 @@ is-ssh@^1.4.0: dependencies: protocols "^2.0.1" -is-stream@2.0.0: +is-stream@2.0.0, is-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - is-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" @@ -4727,10 +4881,10 @@ just-diff-apply@^5.2.0: resolved "https://registry.yarnpkg.com/just-diff-apply/-/just-diff-apply-5.5.0.tgz#771c2ca9fa69f3d2b54e7c3f5c1dfcbcc47f9f0f" integrity sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw== -just-diff@^5.0.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-5.2.0.tgz#60dca55891cf24cd4a094e33504660692348a241" - integrity sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw== +just-diff@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-6.0.0.tgz#77ebd7ee7fbb22f887dbe1dc376e5f781ea0c9c5" + integrity sha512-MbEkhMEa9p7bVD/U29cTM6zUHcLPWwSZjnSquOu++6GyKfoc3aGNdsp2uLQ3Zq0ocg60MzTxwB9qjqwgoQu3+g== keyv@^4.5.2: version "4.5.2" @@ -4763,14 +4917,15 @@ latest-version@^7.0.0: dependencies: package-json "^8.1.0" -lerna@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-6.5.1.tgz#eb89698e5b2891f5681f39d980f63d0519fc464f" - integrity sha512-Va1bysubwWdoWZ1ncKcoTGBXNAu/10/TwELb550TTivXmEWjCCdek4eX0BNLTEYKxu3tpV2UEeqVisUiWGn4WA== +lerna@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/lerna/-/lerna-6.6.0.tgz#385dcf9a88ddd9e62112f03bcfc2ce9e75e64980" + integrity sha512-E1uxpcKVkXPL7IZd8jXmoGlES878M7ConEpkX1o+KTs99ir9c3StIOnrhULYHP3VacUyjtxAPyPCCSg6rIipaw== dependencies: - "@lerna/child-process" "6.5.1" - "@lerna/create" "6.5.1" - "@npmcli/arborist" "5.3.0" + "@lerna/child-process" "6.6.0" + "@lerna/create" "6.6.0" + "@lerna/legacy-package-management" "6.6.0" + "@npmcli/arborist" "6.2.3" "@npmcli/run-script" "4.1.7" "@nrwl/devkit" ">=15.5.2 < 16" "@octokit/plugin-enterprise-rest" "6.0.1" @@ -4812,7 +4967,7 @@ lerna@^6.5.1: node-fetch "2.6.7" npm-package-arg "8.1.1" npm-packlist "5.1.1" - npm-registry-fetch "13.3.0" + npm-registry-fetch "^14.0.3" npmlog "^6.0.2" nx ">=15.5.2 < 16" p-map "4.0.0" @@ -4821,14 +4976,14 @@ lerna@^6.5.1: p-queue "6.6.2" p-reduce "2.1.0" p-waterfall "2.1.1" - pacote "13.6.1" + pacote "13.6.2" path-exists "4.0.0" pify "5.0.0" read-cmd-shim "3.0.0" read-package-json "5.0.1" resolve-from "5.0.0" rimraf "^3.0.2" - semver "7.3.4" + semver "^7.3.8" signal-exit "3.0.7" slash "3.0.0" ssri "9.0.1" @@ -4882,10 +5037,10 @@ libnpmpublish@6.0.4: semver "^7.3.7" ssri "^9.0.0" -lilconfig@2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" - integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== +lilconfig@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== lines-and-columns@^1.1.6: version "1.2.4" @@ -4904,29 +5059,29 @@ linkify-it@^3.0.1: dependencies: uc.micro "^1.0.1" -lint-staged@>=13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.1.2.tgz#443636a0cfd834d5518d57d228130dc04c83d6fb" - integrity sha512-K9b4FPbWkpnupvK3WXZLbgu9pchUJ6N7TtVZjbaPsoizkqFUDkUReUL25xdrCljJs7uLUF3tZ7nVPeo/6lp+6w== +lint-staged@>=13.2.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.0.tgz#b7abaf79c91cd36d824f17b23a4ce5209206126a" + integrity sha512-GbyK5iWinax5Dfw5obm2g2ccUiZXNGtAS4mCbJ0Lv4rq6iEtfBSjOYdcbOtAIFtM114t0vdpViDDetjVTSd8Vw== dependencies: + chalk "5.2.0" cli-truncate "^3.1.0" - colorette "^2.0.19" - commander "^9.4.1" + commander "^10.0.0" debug "^4.3.4" - execa "^6.1.0" - lilconfig "2.0.6" - listr2 "^5.0.5" + execa "^7.0.0" + lilconfig "2.1.0" + listr2 "^5.0.7" micromatch "^4.0.5" normalize-path "^3.0.0" - object-inspect "^1.12.2" + object-inspect "^1.12.3" pidtree "^0.6.0" string-argv "^0.3.1" - yaml "^2.1.3" + yaml "^2.2.1" -listr2@^5.0.5: - version "5.0.7" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.7.tgz#de69ccc4caf6bea7da03c74f7a2ffecf3904bd53" - integrity sha512-MD+qXHPmtivrHIDRwPYdfNkrzqDiuaKU/rfBcec3WMyMF3xylQj3jMq344OtvQxz7zaCFViRAeqlr2AFhPvXHw== +listr2@^5.0.7: + version "5.0.8" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.8.tgz#a9379ffeb4bd83a68931a65fb223a11510d6ba23" + integrity sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA== dependencies: cli-truncate "^2.1.0" colorette "^2.0.19" @@ -5103,10 +5258,10 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: - version "7.17.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.17.0.tgz#00c7ba5919e5ea7c69ff94ddabbf32cb09ab805c" - integrity sha512-zSxlVVwOabhVyTi6E8gYv2cr6bXK+8ifYz5/uyJb9feXX6NACVDwY4p5Ut3WC3Ivo/QhpARHU3iujx2xGAYHbQ== +lru-cache@^7.14.1, lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== lunr@^2.3.9: version "2.3.9" @@ -5301,7 +5456,7 @@ minimatch@3.0.5: dependencies: brace-expansion "^1.1.7" -minimatch@5.0.1: +minimatch@5.0.1, minimatch@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== @@ -5315,24 +5470,17 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^5.0.1: - version "5.1.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^6.1.0, minimatch@^6.1.6, minimatch@^6.2.0: +minimatch@^6.1.0, minimatch@^6.1.6: version "6.2.0" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-6.2.0.tgz#2b70fd13294178c69c04dfc05aebdb97a4e79e42" integrity sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg== dependencies: brace-expansion "^2.0.1" -minimatch@^7.1.3: - version "7.2.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.2.0.tgz#741ff59370007ebb8faff0a9b20cdb44357803e4" - integrity sha512-rMRHmwySzopAQjmWW6TkAKCEDKNaY/HuV/c2YkWWuWnfkTwApt0V4hnYzzPnZ/5Gcd2+8MPncSyuOGPl3xPvcg== +minimatch@^7.1.3, minimatch@^7.4.1, minimatch@^7.4.2, minimatch@^7.4.3: + version "7.4.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.3.tgz#012cbf110a65134bb354ae9773b55256cdb045a2" + integrity sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A== dependencies: brace-expansion "^2.0.1" @@ -5345,16 +5493,11 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@1.2.7: +minimist@1.2.7, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: version "1.2.7" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - minipass-collect@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" @@ -5420,10 +5563,10 @@ minipass@^3.0.0, minipass@^3.1.1, minipass@^3.1.6: dependencies: yallist "^4.0.0" -minipass@^4.0.0: - version "4.2.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.4.tgz#7d0d97434b6a19f59c5c3221698b48bbf3b2cd06" - integrity sha512-lwycX3cBMTvcejsHITUgYj6Gy6A7Nh4Q6h9NP4sTHY1ccJlC7yKzDmiShEHsJ16Jf1nKGDEaiHxiltsJEvk0nQ== +minipass@^4.0.0, minipass@^4.0.2, minipass@^4.2.4: + version "4.2.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.5.tgz#9e0e5256f1e3513f8c34691dd68549e85b2c8ceb" + integrity sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q== minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" @@ -5555,20 +5698,13 @@ node-addon-api@^3.2.1: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== -node-fetch@2.6.7: +node-fetch@2.6.7, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.7: - version "2.6.9" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" - integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== - dependencies: - whatwg-url "^5.0.0" - node-gyp-build@^4.3.0: version "4.6.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" @@ -5610,13 +5746,6 @@ node-wifi@^2.0.16: command-line-args "^5.2.0" command-line-usage "^6.1.1" -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - nopt@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d" @@ -5624,6 +5753,13 @@ nopt@^6.0.0: dependencies: abbrev "^1.0.0" +nopt@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.1.0.tgz#91f6a3366182176e72ecab93a09c19b63b485f28" + integrity sha512-ZFPLe9Iu0tnx7oWhFxAo4s7QTn8+NNDDxYNaKLjE7Dp0tbakQ3M1QhQzsnzXHQBTUO3K9BmwaxnyO8Ayn2I95Q== + dependencies: + abbrev "^2.0.0" + normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -5681,13 +5817,6 @@ npm-bundled@^1.1.1, npm-bundled@^1.1.2: dependencies: npm-normalize-package-bin "^1.0.1" -npm-bundled@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-2.0.1.tgz#94113f7eb342cd7a67de1e789f896b04d2c600f4" - integrity sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw== - dependencies: - npm-normalize-package-bin "^2.0.0" - npm-bundled@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-3.0.0.tgz#7e8e2f8bb26b794265028491be60321a25a39db7" @@ -5695,13 +5824,13 @@ npm-bundled@^3.0.0: dependencies: npm-normalize-package-bin "^3.0.0" -npm-check-updates@^16.7.9: - version "16.7.9" - resolved "https://registry.yarnpkg.com/npm-check-updates/-/npm-check-updates-16.7.9.tgz#b30e21eb27a9b9f590f96ef9eb0f128a09aaf216" - integrity sha512-2/T9PB0W1uABB1N11jdnPauqNLXMhPUyC0DBeeGlUktcGl/412f40iqFsnNGCqIAag/C37SjLNiW2/yuD7Salw== +npm-check-updates@^16.8.0: + version "16.8.0" + resolved "https://registry.yarnpkg.com/npm-check-updates/-/npm-check-updates-16.8.0.tgz#43884cc479f03d274c9ca9e3150e6fb64412377e" + integrity sha512-2xpFtUPa2OyswC8kpIpxRqQcP/D0uqaBgfiOQAtvGlnDhmHr3QwR2gWjjWtS6xnNvgyyVly/4edY0Uu24c46ew== dependencies: chalk "^5.2.0" - cli-table "^0.3.11" + cli-table3 "^0.6.3" commander "^10.0.0" fast-memoize "^2.5.2" find-up "5.0.0" @@ -5709,19 +5838,19 @@ npm-check-updates@^16.7.9: get-stdin "^8.0.0" globby "^11.0.4" hosted-git-info "^5.1.0" - ini "^3.0.1" + ini "^4.0.0" json-parse-helpfulerror "^1.0.3" jsonlines "^0.1.1" lodash "^4.17.21" - minimatch "^6.2.0" + minimatch "^7.4.3" p-map "^4.0.0" - pacote "15.1.0" + pacote "15.1.1" parse-github-url "^1.0.2" progress "^2.0.3" prompts-ncu "^2.5.1" rc-config-loader "^4.1.2" remote-git-tags "^3.0.0" - rimraf "^4.1.2" + rimraf "^4.4.1" semver "^7.3.8" semver-utils "^1.1.4" source-map-support "^0.5.21" @@ -5769,7 +5898,7 @@ npm-package-arg@8.1.1: semver "^7.0.0" validate-npm-package-name "^3.0.0" -npm-package-arg@^10.0.0: +npm-package-arg@^10.0.0, npm-package-arg@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-10.1.0.tgz#827d1260a683806685d17193073cc152d3c7e9b1" integrity sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA== @@ -5789,7 +5918,7 @@ npm-package-arg@^9.0.0, npm-package-arg@^9.0.1: semver "^7.3.5" validate-npm-package-name "^4.0.0" -npm-packlist@5.1.1: +npm-packlist@5.1.1, npm-packlist@^5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-5.1.1.tgz#79bcaf22a26b6c30aa4dd66b976d69cc286800e0" integrity sha512-UfpSvQ5YKwctmodvPPkK6Fwk603aoVsf8AEbmVKAEECrfvL8SSe1A2YIwrJ6xmTHAITKPwwZsWo7WwEbNk0kxw== @@ -5799,16 +5928,6 @@ npm-packlist@5.1.1: npm-bundled "^1.1.2" npm-normalize-package-bin "^1.0.1" -npm-packlist@^5.1.0: - version "5.1.3" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-5.1.3.tgz#69d253e6fd664b9058b85005905012e00e69274b" - integrity sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg== - dependencies: - glob "^8.0.1" - ignore-walk "^5.0.1" - npm-bundled "^2.0.0" - npm-normalize-package-bin "^2.0.0" - npm-packlist@^7.0.0: version "7.0.4" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-7.0.4.tgz#033bf74110eb74daf2910dc75144411999c5ff32" @@ -5826,7 +5945,7 @@ npm-pick-manifest@^7.0.0: npm-package-arg "^9.0.0" semver "^7.3.5" -npm-pick-manifest@^8.0.0: +npm-pick-manifest@^8.0.0, npm-pick-manifest@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz#c6acd97d1ad4c5dbb80eac7b386b03ffeb289e5f" integrity sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA== @@ -5836,18 +5955,18 @@ npm-pick-manifest@^8.0.0: npm-package-arg "^10.0.0" semver "^7.3.5" -npm-registry-fetch@13.3.0: - version "13.3.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-13.3.0.tgz#0ce10fa4a699a1e70685ecf41bbfb4150d74231b" - integrity sha512-10LJQ/1+VhKrZjIuY9I/+gQTvumqqlgnsCufoXETHAPFTS3+M+Z5CFhZRDHGavmJ6rOye3UvNga88vl8n1r6gg== +npm-registry-fetch@14.0.3, npm-registry-fetch@^14.0.0, npm-registry-fetch@^14.0.3: + version "14.0.3" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz#8545e321c2b36d2c6fe6e009e77e9f0e527f547b" + integrity sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA== dependencies: - make-fetch-happen "^10.0.6" - minipass "^3.1.6" - minipass-fetch "^2.0.3" + make-fetch-happen "^11.0.0" + minipass "^4.0.0" + minipass-fetch "^3.0.0" minipass-json-stream "^1.0.1" minizlib "^2.1.2" - npm-package-arg "^9.0.1" - proc-log "^2.0.0" + npm-package-arg "^10.0.0" + proc-log "^3.0.0" npm-registry-fetch@^13.0.0, npm-registry-fetch@^13.0.1: version "13.3.1" @@ -5862,19 +5981,6 @@ npm-registry-fetch@^13.0.0, npm-registry-fetch@^13.0.1: npm-package-arg "^9.0.1" proc-log "^2.0.0" -npm-registry-fetch@^14.0.0: - version "14.0.3" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz#8545e321c2b36d2c6fe6e009e77e9f0e527f547b" - integrity sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA== - dependencies: - make-fetch-happen "^11.0.0" - minipass "^4.0.0" - minipass-fetch "^3.0.0" - minipass-json-stream "^1.0.1" - minizlib "^2.1.2" - npm-package-arg "^10.0.0" - proc-log "^3.0.0" - npm-run-all@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" @@ -5904,7 +6010,7 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" -npmlog@^6.0.0, npmlog@^6.0.2: +npmlog@6.0.2, npmlog@^6.0.0, npmlog@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== @@ -5914,6 +6020,16 @@ npmlog@^6.0.0, npmlog@^6.0.2: gauge "^4.0.3" set-blocking "^2.0.0" +npmlog@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-7.0.1.tgz#7372151a01ccb095c47d8bf1d0771a4ff1f53ac8" + integrity sha512-uJ0YFk/mCQpLBt+bxN88AKd+gyqZvZDbtiNxk6Waqcj2aPRyfVx8ITawkyQynxUagInjdYT1+qj4NfA5KJJUxg== + dependencies: + are-we-there-yet "^4.0.0" + console-control-strings "^1.1.0" + gauge "^5.0.0" + set-blocking "^2.0.0" + nx@15.7.2, "nx@>=15.5.2 < 16": version "15.7.2" resolved "https://registry.yarnpkg.com/nx/-/nx-15.7.2.tgz#048f8968420f5d56a1f464a83c8c3e84dfc95bf4" @@ -5998,7 +6114,7 @@ nyc@^15.1.0: test-exclude "^6.0.0" yargs "^15.0.2" -object-inspect@^1.12.2, object-inspect@^1.9.0: +object-inspect@^1.12.2, object-inspect@^1.12.3, object-inspect@^1.9.0: version "1.12.3" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== @@ -6239,10 +6355,10 @@ package-json@^8.1.0: registry-url "^6.0.0" semver "^7.3.7" -pacote@13.6.1: - version "13.6.1" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-13.6.1.tgz#ac6cbd9032b4c16e5c1e0c60138dfe44e4cc589d" - integrity sha512-L+2BI1ougAPsFjXRyBhcKmfT016NscRFLv6Pz5EiNf1CCFJFU0pSKKQwsZTyAQB+sTuUL4TyFyp6J1Ork3dOqw== +pacote@13.6.2, pacote@^13.6.1: + version "13.6.2" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-13.6.2.tgz#0d444ba3618ab3e5cd330b451c22967bbd0ca48a" + integrity sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg== dependencies: "@npmcli/git" "^3.0.0" "@npmcli/installed-package-contents" "^1.0.7" @@ -6266,10 +6382,10 @@ pacote@13.6.1: ssri "^9.0.0" tar "^6.1.11" -pacote@15.1.0: - version "15.1.0" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-15.1.0.tgz#2e0b12a4f55ffd801a8134a1ae28ef361dc3f243" - integrity sha512-FFcjtIl+BQNfeliSm7MZz5cpdohvUV1yjGnqgVM4UnVF7JslRY0ImXAygdaCDV0jjUADEWu4y5xsDV8brtrTLg== +pacote@15.1.1, pacote@^15.0.0, pacote@^15.0.8: + version "15.1.1" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-15.1.1.tgz#94d8c6e0605e04d427610b3aacb0357073978348" + integrity sha512-eeqEe77QrA6auZxNHIp+1TzHQ0HBKf5V6c8zcaYZ134EJe1lCi+fjXATkNiEEfbG+e50nu02GLvUtmZcGOYabQ== dependencies: "@npmcli/git" "^4.0.0" "@npmcli/installed-package-contents" "^2.0.1" @@ -6290,33 +6406,6 @@ pacote@15.1.0: ssri "^10.0.0" tar "^6.1.11" -pacote@^13.0.3, pacote@^13.6.1: - version "13.6.2" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-13.6.2.tgz#0d444ba3618ab3e5cd330b451c22967bbd0ca48a" - integrity sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg== - dependencies: - "@npmcli/git" "^3.0.0" - "@npmcli/installed-package-contents" "^1.0.7" - "@npmcli/promise-spawn" "^3.0.0" - "@npmcli/run-script" "^4.1.0" - cacache "^16.0.0" - chownr "^2.0.0" - fs-minipass "^2.1.0" - infer-owner "^1.0.4" - minipass "^3.1.6" - mkdirp "^1.0.4" - npm-package-arg "^9.0.0" - npm-packlist "^5.1.0" - npm-pick-manifest "^7.0.0" - npm-registry-fetch "^13.0.1" - proc-log "^2.0.0" - promise-retry "^2.0.1" - read-package-json "^5.0.0" - read-package-json-fast "^2.0.3" - rimraf "^3.0.2" - ssri "^9.0.0" - tar "^6.1.11" - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -6324,13 +6413,13 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-conflict-json@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/parse-conflict-json/-/parse-conflict-json-2.0.2.tgz#3d05bc8ffe07d39600dc6436c6aefe382033d323" - integrity sha512-jDbRGb00TAPFsKWCpZZOT93SxVP9nONOSgES3AevqRq/CHvavEBvKAjxX9p5Y5F0RZLxH9Ufd9+RwtCsa+lFDA== +parse-conflict-json@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz#67dc55312781e62aa2ddb91452c7606d1969960c" + integrity sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw== dependencies: - json-parse-even-better-errors "^2.3.1" - just-diff "^5.0.1" + json-parse-even-better-errors "^3.0.0" + just-diff "^6.0.0" just-diff-apply "^5.2.0" parse-github-url@^1.0.2: @@ -6418,6 +6507,14 @@ path-parse@^1.0.6, path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.6.1: + version "1.6.3" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.6.3.tgz#4eba7183d64ef88b63c7d330bddc3ba279dc6c40" + integrity sha512-RAmB+n30SlN+HnNx6EbcpoDy9nwdpcGPnEKrJnu6GZoDWBdIjo1UQMVtW2ybtC7LC2oKLcMq8y5g8WnKLiod9g== + dependencies: + lru-cache "^7.14.1" + minipass "^4.0.2" + path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -6490,6 +6587,14 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +postcss-selector-parser@^6.0.10: + version "6.0.11" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" + integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -6507,10 +6612,19 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@2.8.4: - version "2.8.4" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3" - integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw== +prettier@2.8.6: + version "2.8.6" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.6.tgz#5c174b29befd507f14b83e3c19f83fdc0e974b71" + integrity sha512-mtuzdiBbHwPEgl7NxWlqOkithPyp4VN93V7VeHVWBF+ad3I5avc0RVDT4oImXQy9H/AqxA2NSQH8pSxHW6FYbQ== + +pretty-format@29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.4.3.tgz#25500ada21a53c9e8423205cf0337056b201244c" + integrity sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA== + dependencies: + "@jest/schemas" "^29.4.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" proc-log@^2.0.0, proc-log@^2.0.1: version "2.0.1" @@ -6534,6 +6648,11 @@ process-on-spawn@^1.0.0: dependencies: fromentries "^1.2.0" +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + progress@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -6690,17 +6809,22 @@ rc@1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + read-cmd-shim@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-3.0.0.tgz#62b8c638225c61e6cc607f8f4b779f3b8238f155" integrity sha512-KQDVjGqhZk92PPNRj9ZEXEuqg8bUobSKRw+q0YQ3TKI5xkce7bUJobL4Z/OtiEbAAv70yEpYIXp4iQ9L8oPVog== -read-cmd-shim@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-3.0.1.tgz#868c235ec59d1de2db69e11aec885bc095aea087" - integrity sha512-kEmDUoYf/CDy8yZbLTmhB1X9kkjf9Q80PCNsDMb7ufrGd6zZSQA1+UyjrO+pZm5K/S4OXCWJeiIt1JA8kAsa6g== +read-cmd-shim@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz#640a08b473a49043e394ae0c7a34dd822c73b9bb" + integrity sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q== -read-package-json-fast@^2.0.2, read-package-json-fast@^2.0.3: +read-package-json-fast@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== @@ -6708,7 +6832,7 @@ read-package-json-fast@^2.0.2, read-package-json-fast@^2.0.3: json-parse-even-better-errors "^2.3.0" npm-normalize-package-bin "^1.0.1" -read-package-json-fast@^3.0.0: +read-package-json-fast@^3.0.0, read-package-json-fast@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz#394908a9725dc7a5f14e70c8e7556dff1d2b1049" integrity sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw== @@ -6716,7 +6840,7 @@ read-package-json-fast@^3.0.0: json-parse-even-better-errors "^3.0.0" npm-normalize-package-bin "^3.0.0" -read-package-json@5.0.1: +read-package-json@5.0.1, read-package-json@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-5.0.1.tgz#1ed685d95ce258954596b13e2e0e76c7d0ab4c26" integrity sha512-MALHuNgYWdGW3gKzuNMuYtcSSZbGQm94fAp16xt8VsYTLBjUSc55bLMKe6gzpWue0Tfi6CBgwCSdDAqutGDhMg== @@ -6726,16 +6850,6 @@ read-package-json@5.0.1: normalize-package-data "^4.0.0" npm-normalize-package-bin "^1.0.1" -read-package-json@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-5.0.2.tgz#b8779ccfd169f523b67208a89cc912e3f663f3fa" - integrity sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q== - dependencies: - glob "^8.0.1" - json-parse-even-better-errors "^2.3.1" - normalize-package-data "^4.0.0" - npm-normalize-package-bin "^2.0.0" - read-package-json@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-6.0.0.tgz#6a741841ad72a40e77a82b9c3c8c10e865bbc519" @@ -6798,6 +6912,16 @@ readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stre string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.3.0.tgz#0914d0c72db03b316c9733bb3461d64a3cc50cba" + integrity sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ== + dependencies: + abort-controller "^3.0.0" + buffer "^6.0.3" + events "^3.3.0" + process "^0.11.10" + readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" @@ -6811,16 +6935,6 @@ readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readdir-scoped-modules@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" - integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== - dependencies: - debuglog "^1.0.1" - dezalgo "^1.0.0" - graceful-fs "^4.1.2" - once "^1.3.0" - readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -6862,7 +6976,7 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.1.3" functions-have-names "^1.2.2" -regexpp@^3.0.0, regexpp@^3.2.0: +regexpp@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== @@ -7006,10 +7120,12 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" -rimraf@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.1.2.tgz#20dfbc98083bdfaa28b01183162885ef213dbf7c" - integrity sha512-BlIbgFryTbw3Dz6hyoWFhKk+unCcHMSkZGrTFVAx2WmttdBSonsdtRlwiuTbDqTKr+UlXIUqJVS4QT5tUzGENQ== +rimraf@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.1.tgz#bd33364f67021c5b79e93d7f4fa0568c7c21b755" + integrity sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og== + dependencies: + glob "^9.2.0" run-async@^2.4.0: version "2.4.1" @@ -7030,12 +7146,7 @@ rxjs@^7.5.5, rxjs@^7.8.0: dependencies: tslib "^2.1.0" -safe-buffer@^5.1.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -7331,7 +7442,7 @@ ssri@9.0.1, ssri@^9.0.0: dependencies: minipass "^3.1.1" -ssri@^10.0.0: +ssri@^10.0.0, ssri@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.1.tgz#c61f85894bbc6929fc3746f05e31cf5b44c030d5" integrity sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw== @@ -7388,14 +7499,7 @@ string.prototype.trimstart@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: +string_decoder@^1.1.1, string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== @@ -7535,7 +7639,7 @@ tar-stream@~2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@6.1.11: +tar@6.1.11, tar@^6.1.11, tar@^6.1.2: version "6.1.11" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== @@ -7547,23 +7651,27 @@ tar@6.1.11: mkdirp "^1.0.3" yallist "^4.0.0" -tar@^6.1.11, tar@^6.1.2: - version "6.1.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b" - integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw== - dependencies: - chownr "^2.0.0" - fs-minipass "^2.0.0" - minipass "^4.0.0" - minizlib "^2.1.1" - mkdirp "^1.0.3" - yallist "^4.0.0" - temp-dir@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" integrity sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ== +temp-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" + integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== + +tempy@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tempy/-/tempy-1.0.0.tgz#4f192b3ee3328a2684d0e3fc5c491425395aab65" + integrity sha512-eLXG5B1G0mRPHmgH2WydPl5v4jH35qEn3y/rA/aahKhIa91Pn119SsU7n7v/433gtT9ONzC8ISvNHIh2JSTm0w== + dependencies: + del "^6.0.0" + is-stream "^2.0.0" + temp-dir "^2.0.0" + type-fest "^0.16.0" + unique-string "^2.0.0" + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -7611,11 +7719,6 @@ tiny-glob@^0.2.9: globalyzer "0.1.0" globrex "^0.1.2" -tiny-typed-emitter@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz#b3b027fdd389ff81a152c8e847ee2f5be9fad7b5" - integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA== - tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -7647,10 +7750,10 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -treeverse@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-2.0.0.tgz#036dcef04bc3fd79a9b79a68d4da03e882d8a9ca" - integrity sha512-N5gJCkLu1aXccpOTtqV6ddSEi6ZmGkh3hjmbu1IjcavJK4qyOVQmi0myQKM7z5jVGmD68SJoliaVrMmVObhj6A== +treeverse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-3.0.0.tgz#dd82de9eb602115c6ebd77a574aae67003cb48c8" + integrity sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ== trim-newlines@^3.0.0: version "3.0.1" @@ -7739,6 +7842,11 @@ type-detect@^4.0.0, type-detect@^4.0.5: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-fest@^0.16.0: + version "0.16.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.16.0.tgz#3240b891a78b0deae910dbeb86553e552a148860" + integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg== + type-fest@^0.18.0: version "0.18.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" @@ -7805,17 +7913,17 @@ typedoc-plugin-resolve-crossmodule-references@^0.3.3: resolved "https://registry.yarnpkg.com/typedoc-plugin-resolve-crossmodule-references/-/typedoc-plugin-resolve-crossmodule-references-0.3.3.tgz#812a6e7083f46031c69fe0021bb3913b10bd68cb" integrity sha512-ZWWBy2WR8z9a6iXYGlyB3KrpV+JDdZv1mndYU6Eh6mInrfMCrQJi3Y5K9ihMBfuaBGB//le1nEmQLgzU3IO+dw== -typedoc@^0.23.25: - version "0.23.26" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.23.26.tgz#ae082683698bad68757d8fe619242a56d6b5bf36" - integrity sha512-5m4KwR5tOLnk0OtMaRn9IdbeRM32uPemN9kur7YK9wFqx8U0CYrvO9aVq6ysdZSV1c824BTm+BuQl2Ze/k1HtA== +typedoc@^0.23.28: + version "0.23.28" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.23.28.tgz#3ce9c36ef1c273fa849d2dea18651855100d3ccd" + integrity sha512-9x1+hZWTHEQcGoP7qFmlo4unUoVJLB0H/8vfO/7wqTnZxg4kPuji9y3uRzEu0ZKez63OJAUmiGhUrtukC6Uj3w== dependencies: lunr "^2.3.9" marked "^4.2.12" minimatch "^7.1.3" shiki "^0.14.1" -"typescript@^3 || ^4", typescript@^4.6.4, typescript@^4.9.5: +"typescript@^3 || ^4", "typescript@^4.6.4 || ^5.0.0", typescript@^4.9.5: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== @@ -7883,6 +7991,13 @@ unique-slug@^4.0.0: dependencies: imurmurhash "^0.1.4" +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + unique-string@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-3.0.0.tgz#84a1c377aff5fd7a8bc6b55d8244b2bd90d75b9a" @@ -7910,7 +8025,7 @@ untildify@^4.0.0: resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== -upath@^2.0.1: +upath@2.0.1, upath@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== @@ -7950,7 +8065,7 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util-deprecate@^1.0.1, util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -8186,10 +8301,10 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write-file-atomic@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" - integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== +write-file-atomic@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.0.tgz#54303f117e109bf3d540261125c8ea5a7320fab0" + integrity sha512-R7NYMnHSlV42K54lwY9lvW6MnSm1HSJqZL3xiSgi9E7//FYaI74r2G0rd+/X6VAMkHEdzxQaU5HUOXWUz5kA/w== dependencies: imurmurhash "^0.1.4" signal-exit "^3.0.7" @@ -8255,12 +8370,12 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yaml@^2.1.3, yaml@^2.2.1: +yaml@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.1.tgz#3014bf0482dcd15147aa8e56109ce8632cd60ce4" integrity sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw== -yargs-parser@20.2.4: +yargs-parser@20.2.4, yargs-parser@^20.2.2, yargs-parser@^20.2.3: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== @@ -8278,11 +8393,6 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^20.2.2, yargs-parser@^20.2.3: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - yargs-unparser@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"