├── .gitignore ├── .mocharc.js ├── .npmignore ├── .prettierignore ├── .prettierrc.js ├── .vscode └── launch.json ├── README.md ├── package.json ├── src ├── flv-data.ts ├── flv-stream.ts ├── flv.ts └── index.ts ├── test ├── integration │ └── flv-stream.test.ts └── test.flv ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | -------------------------------------------------------------------------------- /.mocharc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | require: 'ts-node/register', 3 | spec: 'test/**/*.test.ts', 4 | }; 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | test/ 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 80, 3 | singleQuote: true, 4 | trailingComma: 'all', 5 | endOfLine: 'auto', 6 | }; 7 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "current file", 6 | "type": "pwa-node", 7 | "request": "launch", 8 | "args": ["${relativeFile}"], 9 | "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], 10 | "sourceMaps": true, 11 | "cwd": "${workspaceRoot}", 12 | "skipFiles": ["/**", "**/node_modules/**"] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-flv 2 | 3 | https://www.npmjs.com/package/node-flv 4 | 5 | ## Overview 6 | 7 | The purpose of this package is to give you an ability to parse FLV stream in realtime and get highly structured and strongly typed FLV container data that can be modified and built back into a buffer. Covered with tests. 8 | 9 | ## API 10 | 11 | ```ts 12 | const fileReadStream = fs.createReadStream('file.flv'); 13 | 14 | const flvStream = new FlvStreamParser(); 15 | 16 | flvStream.on('flv-header', (flvHeader: FlvHeader) => { 17 | // this will most certainly fire first 18 | // it's a header of the flv stream 19 | 20 | flvHeader.build(); 21 | }); 22 | 23 | flvStream.on('flv-packet', (flvPacket: FlvPacket) => { 24 | // this is an flv packet itself 25 | // packets can be of three types: audio, video, metadata 26 | // any property of the packet that is not read only can be changed and that will be reflected in the result of the build packet function 27 | 28 | flvPacket.build(); 29 | }); 30 | 31 | // separate events for each packet type for your convenience 32 | 33 | flvStream.on('flv-packet-audio', (flvPacket: FlvPacketAudio) => {}); 34 | 35 | flvStream.on('flv-packet-video', (flvPacket: FlvPacketVideo) => {}); 36 | 37 | flvStream.on('flv-packet-metadata', (flvPacket: FlvPacketMetadata) => {}); 38 | 39 | flvStream.on('flv-packet-unknown', (flvPacket: FlvPacket) => {}); 40 | 41 | fileReadStream.pipe(flvStream); 42 | ``` 43 | 44 | ## FLV Structure and Flow 45 | 46 | FLV is a very structured datatype. It's a container that can hold various video and audio codecs. As an example, it can contain `vp6`, `avc` video codecs and `mp3`, `aac` audio codecs. 47 | 48 | ### Flow 49 | 50 | FLV stream starts with an flv header followed by separate flv packets. Most of the time first flv packet is a metadata packet that contains information about the stream. It's payload is a hash-map of data. 51 | 52 | ```ts 53 | Metadata Example 54 | 55 | { duration: 10.067, 56 | width: 1280, 57 | height: 720, 58 | videodatarate: 1000, 59 | framerate: 30, 60 | videocodecid: 7, 61 | audiodatarate: 125, 62 | audiosamplerate: 48000, 63 | audiosamplesize: 16, 64 | stereo: true, 65 | audiocodecid: 10, 66 | date: '2019-10-05T16:11:08+03:00', 67 | encoder: 'Lavf57.83.100', 68 | filesize: 496576 } 69 | ``` 70 | 71 | Usually followed by a first video and audio packet. These first video and audio packets are important. They should have `timestampLower` of 0, clients (video-players, codec decoders) use these packets in order to initialize the whole stream. So, for example, for video packets these must be key-frame packets, otherwise players wont be able to initialize the render properly. Rest of the sequence after these first packets can vary dramatically. What is expected, of course, is that these next packets have correct values for both timestamp values `timestampLower` and `timestampUpper`. 72 | 73 | ### Structure 74 | 75 | #### FlvHeader 76 | 77 | ```ts 78 | { signature: 'FLV', 79 | version: 1, 80 | flags: 5, 81 | headerSize: 9 } 82 | ``` 83 | 84 | `headerSize - byte length of the header, usually 9, reserved for backwards compatibility once the version changes` 85 | 86 | #### FlvPacket 87 | 88 | Contains flv packet header and a payload. 89 | 90 | ```ts 91 | { header: FlvPacketHeader, 92 | payload: Buffer } 93 | ``` 94 | 95 | #### FlvPacketHeader 96 | 97 | ```ts 98 | { packetTypeId: 18, 99 | payloadSize: 327, 100 | timestampLower: 0, 101 | timestampUpper: 0, 102 | streamId: 0 } 103 | ``` 104 | 105 | `packetTypeId - audio, video, metadata, etc` 106 | 107 | `payloadSize - payload length of the current packet in bytes` 108 | 109 | `timestampLower - timestamp relative to the first packet in milliseconds` 110 | 111 | `timestampUpper - timestamp extension in milliseconds` 112 | 113 | `streamId - always 0` 114 | 115 | #### Official FLV specification guide 116 | 117 | - https://www.adobe.com/content/dam/acom/en/devnet/flv/video_file_format_spec_v10.pdf 118 | 119 | ## Usage Examples 120 | 121 | - https://github.com/rebelvg/flv-server 122 | 123 | - https://github.com/rebelvg/flv-parser-ffmpeg-streamer 124 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-flv", 3 | "version": "0.9.11", 4 | "license": "MIT", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/rebelvg/node-flv.git" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/rebelvg/node-flv/issues" 13 | }, 14 | "homepage": "https://github.com/rebelvg/node-flv#readme", 15 | "keywords": [ 16 | "flv", 17 | "stream", 18 | "typescript" 19 | ], 20 | "scripts": { 21 | "lint": "prettier \"**/*\" --list-different --ignore-unknown", 22 | "lint:fix": "prettier \"**/*\" --write --ignore-unknown", 23 | "build": "tsc", 24 | "test": "mocha", 25 | "release": "yarn lint && yarn test && yarn build && yarn publish" 26 | }, 27 | "dependencies": { 28 | "bitwise": "^0.2.0", 29 | "lodash": "^4.17.20", 30 | "stream-parser": "^0.3.1" 31 | }, 32 | "devDependencies": { 33 | "@types/chai": "^4.2.14", 34 | "@types/lodash": "^4.14.165", 35 | "@types/mocha": "^8.2.0", 36 | "@types/node": "^14.14.13", 37 | "chai": "^4.2.0", 38 | "mocha": "^8.2.1", 39 | "prettier": "^2.2.1", 40 | "ts-node": "^9.1.1", 41 | "typescript": "^4.1.3" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/flv-data.ts: -------------------------------------------------------------------------------- 1 | import * as _ from 'lodash'; 2 | import * as bitwise from 'bitwise'; 3 | 4 | export enum SoundFormatEnum { 5 | 'PCM_PE' = 0, 6 | 'ADPCM' = 1, 7 | 'MP3' = 2, 8 | 'PCM_LE' = 3, 9 | 'NELLYMOSER_16KHZ_MONO' = 4, 10 | 'NELLYMOSER_8KHZ_MONO' = 5, 11 | 'NELLYMOSER' = 6, 12 | 'G.711_A-LAW_PCM' = 7, 13 | 'G.711_MU-LAW_PCM' = 8, 14 | 'RESERVED' = 9, 15 | 'AAC' = 10, 16 | 'SPEEX' = 11, 17 | 'MP3_8KHZ' = 14, 18 | 'DEVICE-SPECIFIC' = 15, 19 | } 20 | 21 | export enum SoundSampleRateEnum { 22 | '5.5KHZ' = 0, 23 | '11KHZ' = 1, 24 | '22KHZ' = 2, 25 | '44KHZ' = 3, 26 | } 27 | 28 | export enum SoundBitDepthEnum { 29 | '8BIT' = 0, 30 | '16BIT' = 1, 31 | } 32 | 33 | export enum SoundChannelsEnum { 34 | 'MONO' = 0, 35 | 'STEREO' = 1, 36 | } 37 | 38 | export enum VideoFrameTypeEnum { 39 | 'KEYFRAME' = 1, 40 | 'INTER_FRAME' = 2, 41 | 'DISPOSABLE_FRAME' = 3, 42 | 'GENERATED_KEYFRAME' = 4, 43 | 'VIDEO_INFO' = 5, 44 | } 45 | 46 | export enum VideoCodecIdEnum { 47 | 'JPEG' = 1, 48 | 'SORENSON_H.263' = 2, 49 | 'SCREEN_VIDEO' = 3, 50 | 'ON2_VP6' = 4, 51 | 'ON2_VP6_WA' = 5, 52 | 'SCREEN_VIDEO_VERSION_2' = 6, 53 | 'AVC' = 7, 54 | } 55 | 56 | export interface IAudioData { 57 | readonly format: SoundFormatEnum; 58 | readonly sampleRate: SoundSampleRateEnum; 59 | readonly bitDepth: SoundBitDepthEnum; 60 | readonly channels: SoundChannelsEnum; 61 | } 62 | 63 | export interface IVideoData { 64 | readonly frameType: VideoFrameTypeEnum; 65 | readonly codecId: VideoCodecIdEnum; 66 | } 67 | 68 | export interface IMetadataData { 69 | readonly [paramName: string]: number | string | boolean; 70 | } 71 | 72 | export function parseAudio(payload: Buffer): IAudioData { 73 | const formatBit: number = bitwise.readUInt(payload, 0, 4); 74 | const sampleRateBit: number = bitwise.readUInt(payload, 4, 2); 75 | const bitDepthBit: number = bitwise.readUInt(payload, 6, 1); 76 | const channelsBit: number = bitwise.readUInt(payload, 7, 1); 77 | 78 | const format = _.find(SoundFormatEnum, (value) => value === formatBit); 79 | const sampleRate = _.find( 80 | SoundSampleRateEnum, 81 | (value) => value === sampleRateBit, 82 | ); 83 | const bitDepth = _.find(SoundBitDepthEnum, (value) => value === bitDepthBit); 84 | const channels = _.find(SoundChannelsEnum, (value) => value === channelsBit); 85 | 86 | if (!_.every([format, sampleRate, bitDepth, channels])) { 87 | throw new Error(`could_not_parse_audio`); 88 | } 89 | 90 | return { 91 | format, 92 | sampleRate, 93 | bitDepth, 94 | channels, 95 | }; 96 | } 97 | 98 | export function parseVideo(payload: Buffer): IVideoData { 99 | const frameTypeBit: number = bitwise.readUInt(payload, 0, 4); 100 | const codecIdBit: number = bitwise.readUInt(payload, 4, 4); 101 | 102 | const frameType = _.find( 103 | VideoFrameTypeEnum, 104 | (value) => value === frameTypeBit, 105 | ); 106 | const codecId = _.find(VideoCodecIdEnum, (value) => value === codecIdBit); 107 | 108 | if (!_.every([frameType, codecId])) { 109 | throw new Error(`could_not_parse_video`); 110 | } 111 | 112 | return { 113 | frameType, 114 | codecId, 115 | }; 116 | } 117 | 118 | export function parseMetadata(payload: Buffer): IMetadataData { 119 | if (payload.readUInt8(0) !== 2) { 120 | throw new Error(`unknown_metadata_format`); 121 | } 122 | 123 | const stringLength = payload.readUIntBE(1, 2); 124 | 125 | let parseOffset = 3; 126 | 127 | const metadataName = payload.toString( 128 | 'utf8', 129 | parseOffset, 130 | parseOffset + stringLength, 131 | ); 132 | 133 | parseOffset += stringLength; 134 | 135 | const metadataObjType = payload.readUInt8(parseOffset); 136 | 137 | if (![3, 8].includes(metadataObjType)) { 138 | throw new Error(`unknown_metadata_type ${metadataObjType}`); 139 | } 140 | 141 | parseOffset++; 142 | 143 | switch (metadataObjType) { 144 | case 3: { 145 | parseOffset += 1; 146 | 147 | break; 148 | } 149 | case 8: { 150 | // number of items in metadata hash-map 151 | const metadataLength = payload.readUInt32BE(parseOffset); 152 | 153 | parseOffset += 5; 154 | 155 | break; 156 | } 157 | } 158 | 159 | const params: any = {}; 160 | 161 | while (true) { 162 | if (parseOffset >= payload.length - 2) break; 163 | 164 | const paramNameLength = payload.readUInt8(parseOffset); 165 | 166 | parseOffset++; 167 | 168 | const paramName = payload.toString( 169 | 'utf8', 170 | parseOffset, 171 | parseOffset + paramNameLength, 172 | ); 173 | 174 | parseOffset += paramNameLength; 175 | 176 | const valueType = payload.readUInt8(parseOffset); 177 | 178 | parseOffset++; 179 | 180 | switch (valueType) { 181 | case 0: { 182 | params[paramName] = payload.readDoubleBE(parseOffset); 183 | 184 | parseOffset += 8; 185 | 186 | break; 187 | } 188 | case 1: { 189 | params[paramName] = Boolean(payload.readUIntBE(parseOffset, 1)); 190 | 191 | parseOffset += 1; 192 | 193 | break; 194 | } 195 | case 2: { 196 | let valueLength = payload.readInt16BE(parseOffset); 197 | 198 | parseOffset += 2; 199 | 200 | params[paramName] = payload.toString( 201 | 'utf8', 202 | parseOffset, 203 | parseOffset + valueLength, 204 | ); 205 | 206 | parseOffset += valueLength; 207 | 208 | break; 209 | } 210 | default: { 211 | throw new Error(`unknown_metadata_value_type ${valueType}`); 212 | } 213 | } 214 | 215 | parseOffset++; 216 | } 217 | 218 | return params; 219 | } 220 | -------------------------------------------------------------------------------- /src/flv-stream.ts: -------------------------------------------------------------------------------- 1 | import { Writable } from 'stream'; 2 | import * as StreamParser from 'stream-parser'; 3 | 4 | import { 5 | FlvHeader, 6 | FlvPacketHeader, 7 | FlvPacket, 8 | FlvPacketType, 9 | FlvPacketAudio, 10 | FlvPacketVideo, 11 | FlvPacketMetadata, 12 | FLV_HEADER_SIZE_BYTES_V1, 13 | FLV_PACKET_PREVIOUS_PACKET_SIZE_BYTES_V1, 14 | FLV_PACKET_HEADER_SIZE_BYTES_V1, 15 | } from './flv'; 16 | 17 | const FLV_READ_FOR_HEADER = FLV_HEADER_SIZE_BYTES_V1; 18 | const FLV_READ_FOR_PACKET_PREVIOUS_PACKET_SIZE = FLV_PACKET_PREVIOUS_PACKET_SIZE_BYTES_V1; 19 | const FLV_READ_FOR_PACKET_HEADER = FLV_PACKET_HEADER_SIZE_BYTES_V1; 20 | 21 | export declare interface FlvStreamParser { 22 | _bytes(bytesLength: number, cb: (data: Buffer, cb: () => void) => void): void; 23 | _skipBytes(bytesLength: number, cb: () => void): void; 24 | } 25 | 26 | export class FlvStreamParser extends Writable { 27 | constructor() { 28 | super(); 29 | 30 | this._bytes(FLV_READ_FOR_HEADER, this.onHeader); 31 | } 32 | 33 | private onHeader(rawHeader: Buffer, cb: () => void) { 34 | const flvHeader = new FlvHeader(rawHeader); 35 | 36 | this.emit('flv-header', flvHeader); 37 | 38 | this._skipBytes( 39 | flvHeader.headerSize - 40 | FLV_READ_FOR_HEADER + 41 | FLV_READ_FOR_PACKET_PREVIOUS_PACKET_SIZE, 42 | () => { 43 | this._bytes(FLV_READ_FOR_PACKET_HEADER, this.onPacketHeader); 44 | }, 45 | ); 46 | 47 | cb(); 48 | } 49 | 50 | private onPacketHeader(rawPacketHeader: Buffer, cb: () => void) { 51 | const flvPacketHeader = new FlvPacketHeader(rawPacketHeader); 52 | 53 | this._bytes( 54 | flvPacketHeader.payloadSize, 55 | (rawPacketBody: Buffer, cb: () => void) => { 56 | const flvPacket = new FlvPacket(flvPacketHeader, rawPacketBody); 57 | 58 | this.emitTypedPacket(flvPacket); 59 | 60 | this._skipBytes(FLV_READ_FOR_PACKET_PREVIOUS_PACKET_SIZE, () => { 61 | this._bytes(FLV_READ_FOR_PACKET_HEADER, this.onPacketHeader); 62 | }); 63 | 64 | cb(); 65 | }, 66 | ); 67 | 68 | cb(); 69 | } 70 | 71 | private emitTypedPacket(flvPacket: FlvPacket) { 72 | this.emit('flv-packet', flvPacket); 73 | 74 | switch (flvPacket.header.type) { 75 | case FlvPacketType.AUDIO: { 76 | return this.emit('flv-packet-audio', new FlvPacketAudio(flvPacket)); 77 | } 78 | case FlvPacketType.VIDEO: { 79 | return this.emit('flv-packet-video', new FlvPacketVideo(flvPacket)); 80 | } 81 | case FlvPacketType.METADATA: { 82 | return this.emit( 83 | 'flv-packet-metadata', 84 | new FlvPacketMetadata(flvPacket), 85 | ); 86 | } 87 | default: { 88 | return this.emit('flv-packet-unknown', flvPacket); 89 | } 90 | } 91 | } 92 | } 93 | 94 | StreamParser(FlvStreamParser.prototype); 95 | -------------------------------------------------------------------------------- /src/flv.ts: -------------------------------------------------------------------------------- 1 | import { 2 | IAudioData, 3 | IVideoData, 4 | IMetadataData, 5 | parseAudio, 6 | parseVideo, 7 | parseMetadata, 8 | } from './flv-data'; 9 | 10 | export enum FlvPacketType { 11 | AUDIO = 'audio', 12 | VIDEO = 'video', 13 | METADATA = 'metadata', 14 | UNKNOWN = 'unknown', 15 | } 16 | 17 | export const FLV_HEADER_SIZE_BYTES_V1 = 9; 18 | export const FLV_PACKET_PREVIOUS_PACKET_SIZE_BYTES_V1 = 4; 19 | export const FLV_PACKET_HEADER_SIZE_BYTES_V1 = 11; 20 | 21 | export class FlvHeader { 22 | public readonly signature: string; 23 | public readonly version: number; 24 | public readonly flags: number; 25 | public readonly headerSize: number; 26 | 27 | constructor(rawHeader: Buffer) { 28 | const signature = rawHeader.toString('utf8', 0, 3); 29 | const version = rawHeader.readUInt8(3); 30 | const flags = rawHeader.readUInt8(4); 31 | const headerSize = rawHeader.readUInt32BE(5); 32 | 33 | if (signature !== 'FLV') { 34 | throw new Error('not_flv'); 35 | } 36 | 37 | this.signature = signature; 38 | this.version = version; 39 | this.flags = flags; 40 | this.headerSize = headerSize; 41 | } 42 | 43 | public build(): Buffer { 44 | const rawBuffer = Buffer.alloc( 45 | this.headerSize + FLV_PACKET_PREVIOUS_PACKET_SIZE_BYTES_V1, 46 | ); 47 | 48 | rawBuffer.write(this.signature); 49 | rawBuffer.writeUInt8(this.version, 3); 50 | rawBuffer.writeUInt8(this.flags, 4); 51 | rawBuffer.writeUInt32BE(this.headerSize, 5); 52 | rawBuffer.writeUInt32BE(0, 9); 53 | 54 | return rawBuffer; 55 | } 56 | } 57 | 58 | export class FlvPacketHeader { 59 | public packetTypeId: number; 60 | public payloadSize: number; 61 | public timestampLower: number; 62 | public timestampUpper: number; 63 | public streamId: number; 64 | 65 | private _size: number; 66 | 67 | constructor(rawPacketHeader: Buffer) { 68 | this.packetTypeId = rawPacketHeader.readUInt8(0); 69 | this.payloadSize = rawPacketHeader.readUIntBE(1, 3); 70 | this.timestampLower = rawPacketHeader.readUIntBE(4, 3); 71 | this.timestampUpper = rawPacketHeader.readUInt8(7); 72 | this.streamId = rawPacketHeader.readUIntBE(8, 3); 73 | 74 | this._size = rawPacketHeader.length; 75 | } 76 | 77 | get type(): FlvPacketType { 78 | switch (this.packetTypeId) { 79 | case 8: { 80 | return FlvPacketType.AUDIO; 81 | } 82 | case 9: { 83 | return FlvPacketType.VIDEO; 84 | } 85 | case 18: { 86 | return FlvPacketType.METADATA; 87 | } 88 | default: { 89 | return FlvPacketType.UNKNOWN; 90 | } 91 | } 92 | } 93 | 94 | get size() { 95 | return this._size; 96 | } 97 | 98 | public build(): Buffer { 99 | const rawBuffer = Buffer.alloc(this._size); 100 | 101 | rawBuffer.writeUInt8(this.packetTypeId, 0); 102 | rawBuffer.writeUIntBE(this.payloadSize, 1, 3); 103 | rawBuffer.writeUIntBE(this.timestampLower, 4, 3); 104 | rawBuffer.writeUInt8(this.timestampUpper, 7); 105 | rawBuffer.writeUIntBE(this.streamId, 8, 3); 106 | 107 | return rawBuffer; 108 | } 109 | } 110 | 111 | export class FlvPacket { 112 | public readonly header: FlvPacketHeader; 113 | public readonly payload: Buffer; 114 | public readonly data: any; 115 | 116 | constructor(flvPacketHeader: FlvPacketHeader, payload: Buffer) { 117 | this.header = flvPacketHeader; 118 | this.payload = payload; 119 | } 120 | 121 | public parsePayload(): FlvPacket { 122 | switch (this.header.type) { 123 | case FlvPacketType.AUDIO: { 124 | return new FlvPacketAudio(this); 125 | } 126 | case FlvPacketType.VIDEO: { 127 | return new FlvPacketVideo(this); 128 | } 129 | case FlvPacketType.METADATA: { 130 | return new FlvPacketMetadata(this); 131 | } 132 | default: { 133 | return this; 134 | } 135 | } 136 | } 137 | 138 | public get type(): FlvPacketType { 139 | return this.header.type; 140 | } 141 | 142 | public get size(): number { 143 | return this.header.size + this.payload.length; 144 | } 145 | 146 | public build(): Buffer { 147 | const prevPacketSize = Buffer.alloc(4); 148 | prevPacketSize.writeUInt32BE(this.size, 0); 149 | 150 | return Buffer.concat([this.header.build(), this.payload, prevPacketSize]); 151 | } 152 | 153 | public get isAudioPacket() { 154 | return this.header.type === FlvPacketType.AUDIO; 155 | } 156 | 157 | public get isVideoPacket() { 158 | return this.header.type === FlvPacketType.VIDEO; 159 | } 160 | 161 | public get isMetadataPacket() { 162 | return this.header.type === FlvPacketType.METADATA; 163 | } 164 | 165 | public get isUnknownPacket() { 166 | return this.header.type === FlvPacketType.UNKNOWN; 167 | } 168 | 169 | public get timestamp() { 170 | return this.header.timestampLower; 171 | } 172 | } 173 | 174 | export class FlvPacketAudio extends FlvPacket { 175 | public readonly data: IAudioData; 176 | 177 | constructor({ header, payload }: FlvPacket) { 178 | super(header, payload); 179 | 180 | this.data = parseAudio(payload); 181 | } 182 | } 183 | 184 | export class FlvPacketVideo extends FlvPacket { 185 | public readonly data: IVideoData; 186 | 187 | constructor({ header, payload }: FlvPacket) { 188 | super(header, payload); 189 | 190 | this.data = parseVideo(payload); 191 | } 192 | } 193 | 194 | export class FlvPacketMetadata extends FlvPacket { 195 | public readonly data: IMetadataData; 196 | 197 | constructor({ header, payload }: FlvPacket) { 198 | super(header, payload); 199 | 200 | this.data = parseMetadata(payload); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | FlvHeader, 3 | FlvPacket, 4 | FlvPacketHeader, 5 | FlvPacketAudio, 6 | FlvPacketVideo, 7 | FlvPacketMetadata, 8 | FlvPacketType, 9 | } from './flv'; 10 | export { FlvStreamParser } from './flv-stream'; 11 | -------------------------------------------------------------------------------- /test/integration/flv-stream.test.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | import { assert } from 'chai'; 4 | 5 | import { 6 | FlvStreamParser, 7 | FlvHeader, 8 | FlvPacket, 9 | FlvPacketAudio, 10 | FlvPacketVideo, 11 | FlvPacketMetadata, 12 | } from '../../src'; 13 | 14 | describe('FlvStreamParser integration test', () => { 15 | describe('#FlvStreamParser', () => { 16 | const filePath = path.join(__dirname, '../test.flv'); 17 | 18 | let parsedFlvHeader: FlvHeader; 19 | const parsedFlvPackets: FlvPacket[] = []; 20 | 21 | let typedPacketsCount = 0; 22 | 23 | before(async () => { 24 | const fileReadStream = fs.createReadStream(filePath); 25 | 26 | const flvStream = new FlvStreamParser(); 27 | 28 | flvStream.on('flv-header', (flvHeader: FlvHeader) => { 29 | parsedFlvHeader = flvHeader; 30 | }); 31 | 32 | flvStream.on('flv-packet', (flvPacket: FlvPacket) => { 33 | parsedFlvPackets.push(flvPacket); 34 | }); 35 | 36 | flvStream.on('flv-packet-audio', (flvPacket: FlvPacketAudio) => { 37 | typedPacketsCount++; 38 | }); 39 | 40 | flvStream.on('flv-packet-video', (flvPacket: FlvPacketVideo) => { 41 | typedPacketsCount++; 42 | }); 43 | 44 | flvStream.on('flv-packet-metadata', (flvPacket: FlvPacketMetadata) => { 45 | typedPacketsCount++; 46 | }); 47 | 48 | flvStream.on('flv-packet-unknown', (flvPacket: FlvPacket) => { 49 | typedPacketsCount++; 50 | }); 51 | 52 | await new Promise((resolve) => { 53 | flvStream.on('close', resolve); 54 | 55 | fileReadStream.pipe(flvStream); 56 | }); 57 | }); 58 | 59 | it('should return the same number of packets on both apis', () => { 60 | assert.strictEqual(typedPacketsCount, parsedFlvPackets.length); 61 | }); 62 | 63 | it('should produce exactly the same output file', () => { 64 | const initialFile = fs.readFileSync(filePath); 65 | 66 | const parsedFile = Buffer.from([ 67 | ...parsedFlvHeader.build(), 68 | ...Buffer.concat( 69 | parsedFlvPackets.map((flvPacker) => flvPacker.build()), 70 | ), 71 | ]); 72 | 73 | assert.deepEqual(parsedFile, initialFile); 74 | }); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /test/test.flv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebelvg/node-flv/e618ac3f2e0c0d82ec68e1e929be700549b14b20/test/test.flv -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2019", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "sourceMap": true, 7 | "incremental": true, 8 | "outDir": "./dist" 9 | }, 10 | "include": ["./src/**/*"] 11 | } 12 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/chai@^4.2.14": 6 | version "4.2.14" 7 | resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.14.tgz#44d2dd0b5de6185089375d976b4ec5caf6861193" 8 | integrity sha512-G+ITQPXkwTrslfG5L/BksmbLUA0M1iybEsmCWPqzSxsRRhJZimBKJkoMi8fr/CPygPTj4zO5pJH7I2/cm9M7SQ== 9 | 10 | "@types/lodash@^4.14.165": 11 | version "4.14.165" 12 | resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.165.tgz#74d55d947452e2de0742bad65270433b63a8c30f" 13 | integrity sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg== 14 | 15 | "@types/mocha@^8.2.0": 16 | version "8.2.0" 17 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.0.tgz#3eb56d13a1de1d347ecb1957c6860c911704bc44" 18 | integrity sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ== 19 | 20 | "@types/node@^14.14.13": 21 | version "14.14.13" 22 | resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.13.tgz#9e425079799322113ae8477297ae6ef51b8e0cdf" 23 | integrity sha512-vbxr0VZ8exFMMAjCW8rJwaya0dMCDyYW2ZRdTyjtrCvJoENMpdUHOT/eTzvgyA5ZnqRZ/sI0NwqAxNHKYokLJQ== 24 | 25 | "@ungap/promise-all-settled@1.1.2": 26 | version "1.1.2" 27 | resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" 28 | integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== 29 | 30 | ansi-colors@4.1.1: 31 | version "4.1.1" 32 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" 33 | integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== 34 | 35 | ansi-regex@^3.0.0: 36 | version "3.0.0" 37 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 38 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 39 | 40 | ansi-regex@^4.1.0: 41 | version "4.1.0" 42 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 43 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== 44 | 45 | ansi-styles@^3.2.0: 46 | version "3.2.1" 47 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 48 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 49 | dependencies: 50 | color-convert "^1.9.0" 51 | 52 | ansi-styles@^4.1.0: 53 | version "4.3.0" 54 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 55 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 56 | dependencies: 57 | color-convert "^2.0.1" 58 | 59 | anymatch@~3.1.1: 60 | version "3.1.1" 61 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" 62 | integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== 63 | dependencies: 64 | normalize-path "^3.0.0" 65 | picomatch "^2.0.4" 66 | 67 | arg@^4.1.0: 68 | version "4.1.3" 69 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" 70 | integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== 71 | 72 | argparse@^1.0.7: 73 | version "1.0.10" 74 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 75 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 76 | dependencies: 77 | sprintf-js "~1.0.2" 78 | 79 | assertion-error@^1.1.0: 80 | version "1.1.0" 81 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" 82 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== 83 | 84 | balanced-match@^1.0.0: 85 | version "1.0.0" 86 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 87 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 88 | 89 | binary-extensions@^2.0.0: 90 | version "2.1.0" 91 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" 92 | integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== 93 | 94 | bitwise@^0.2.0: 95 | version "0.2.0" 96 | resolved "https://registry.yarnpkg.com/bitwise/-/bitwise-0.2.0.tgz#99e5dfbfa4ee1c32073dc242266753c025f1e276" 97 | integrity sha1-meXfv6TuHDIHPcJCJmdTwCXx4nY= 98 | 99 | brace-expansion@^1.1.7: 100 | version "1.1.11" 101 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 102 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 103 | dependencies: 104 | balanced-match "^1.0.0" 105 | concat-map "0.0.1" 106 | 107 | braces@~3.0.2: 108 | version "3.0.2" 109 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 110 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 111 | dependencies: 112 | fill-range "^7.0.1" 113 | 114 | browser-stdout@1.3.1: 115 | version "1.3.1" 116 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 117 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 118 | 119 | buffer-from@^1.0.0: 120 | version "1.1.1" 121 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 122 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== 123 | 124 | camelcase@^5.0.0: 125 | version "5.3.1" 126 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 127 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 128 | 129 | camelcase@^6.0.0: 130 | version "6.2.0" 131 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" 132 | integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== 133 | 134 | chai@^4.2.0: 135 | version "4.2.0" 136 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" 137 | integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== 138 | dependencies: 139 | assertion-error "^1.1.0" 140 | check-error "^1.0.2" 141 | deep-eql "^3.0.1" 142 | get-func-name "^2.0.0" 143 | pathval "^1.1.0" 144 | type-detect "^4.0.5" 145 | 146 | chalk@^4.0.0: 147 | version "4.1.0" 148 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" 149 | integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== 150 | dependencies: 151 | ansi-styles "^4.1.0" 152 | supports-color "^7.1.0" 153 | 154 | check-error@^1.0.2: 155 | version "1.0.2" 156 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 157 | integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= 158 | 159 | chokidar@3.4.3: 160 | version "3.4.3" 161 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" 162 | integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ== 163 | dependencies: 164 | anymatch "~3.1.1" 165 | braces "~3.0.2" 166 | glob-parent "~5.1.0" 167 | is-binary-path "~2.1.0" 168 | is-glob "~4.0.1" 169 | normalize-path "~3.0.0" 170 | readdirp "~3.5.0" 171 | optionalDependencies: 172 | fsevents "~2.1.2" 173 | 174 | cliui@^5.0.0: 175 | version "5.0.0" 176 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" 177 | integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== 178 | dependencies: 179 | string-width "^3.1.0" 180 | strip-ansi "^5.2.0" 181 | wrap-ansi "^5.1.0" 182 | 183 | color-convert@^1.9.0: 184 | version "1.9.3" 185 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 186 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 187 | dependencies: 188 | color-name "1.1.3" 189 | 190 | color-convert@^2.0.1: 191 | version "2.0.1" 192 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 193 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 194 | dependencies: 195 | color-name "~1.1.4" 196 | 197 | color-name@1.1.3: 198 | version "1.1.3" 199 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 200 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 201 | 202 | color-name@~1.1.4: 203 | version "1.1.4" 204 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 205 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 206 | 207 | concat-map@0.0.1: 208 | version "0.0.1" 209 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 210 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 211 | 212 | create-require@^1.1.0: 213 | version "1.1.1" 214 | resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" 215 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== 216 | 217 | debug@2: 218 | version "2.6.9" 219 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 220 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 221 | dependencies: 222 | ms "2.0.0" 223 | 224 | debug@4.2.0: 225 | version "4.2.0" 226 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" 227 | integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== 228 | dependencies: 229 | ms "2.1.2" 230 | 231 | decamelize@^1.2.0: 232 | version "1.2.0" 233 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 234 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= 235 | 236 | decamelize@^4.0.0: 237 | version "4.0.0" 238 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" 239 | integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== 240 | 241 | deep-eql@^3.0.1: 242 | version "3.0.1" 243 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" 244 | integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== 245 | dependencies: 246 | type-detect "^4.0.0" 247 | 248 | diff@4.0.2, diff@^4.0.1: 249 | version "4.0.2" 250 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" 251 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 252 | 253 | emoji-regex@^7.0.1: 254 | version "7.0.3" 255 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 256 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 257 | 258 | escape-string-regexp@4.0.0: 259 | version "4.0.0" 260 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" 261 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 262 | 263 | esprima@^4.0.0: 264 | version "4.0.1" 265 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 266 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 267 | 268 | fill-range@^7.0.1: 269 | version "7.0.1" 270 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 271 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 272 | dependencies: 273 | to-regex-range "^5.0.1" 274 | 275 | find-up@5.0.0: 276 | version "5.0.0" 277 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" 278 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 279 | dependencies: 280 | locate-path "^6.0.0" 281 | path-exists "^4.0.0" 282 | 283 | find-up@^3.0.0: 284 | version "3.0.0" 285 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" 286 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== 287 | dependencies: 288 | locate-path "^3.0.0" 289 | 290 | flat@^5.0.2: 291 | version "5.0.2" 292 | resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" 293 | integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== 294 | 295 | fs.realpath@^1.0.0: 296 | version "1.0.0" 297 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 298 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 299 | 300 | fsevents@~2.1.2: 301 | version "2.1.3" 302 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" 303 | integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== 304 | 305 | get-caller-file@^2.0.1: 306 | version "2.0.5" 307 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 308 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 309 | 310 | get-func-name@^2.0.0: 311 | version "2.0.0" 312 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 313 | integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= 314 | 315 | glob-parent@~5.1.0: 316 | version "5.1.1" 317 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" 318 | integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== 319 | dependencies: 320 | is-glob "^4.0.1" 321 | 322 | glob@7.1.6: 323 | version "7.1.6" 324 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 325 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 326 | dependencies: 327 | fs.realpath "^1.0.0" 328 | inflight "^1.0.4" 329 | inherits "2" 330 | minimatch "^3.0.4" 331 | once "^1.3.0" 332 | path-is-absolute "^1.0.0" 333 | 334 | growl@1.10.5: 335 | version "1.10.5" 336 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 337 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 338 | 339 | has-flag@^4.0.0: 340 | version "4.0.0" 341 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 342 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 343 | 344 | he@1.2.0: 345 | version "1.2.0" 346 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 347 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 348 | 349 | inflight@^1.0.4: 350 | version "1.0.6" 351 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 352 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 353 | dependencies: 354 | once "^1.3.0" 355 | wrappy "1" 356 | 357 | inherits@2: 358 | version "2.0.4" 359 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 360 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 361 | 362 | is-binary-path@~2.1.0: 363 | version "2.1.0" 364 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 365 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 366 | dependencies: 367 | binary-extensions "^2.0.0" 368 | 369 | is-extglob@^2.1.1: 370 | version "2.1.1" 371 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 372 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 373 | 374 | is-fullwidth-code-point@^2.0.0: 375 | version "2.0.0" 376 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 377 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 378 | 379 | is-glob@^4.0.1, is-glob@~4.0.1: 380 | version "4.0.1" 381 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" 382 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== 383 | dependencies: 384 | is-extglob "^2.1.1" 385 | 386 | is-number@^7.0.0: 387 | version "7.0.0" 388 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 389 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 390 | 391 | is-plain-obj@^2.1.0: 392 | version "2.1.0" 393 | resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" 394 | integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== 395 | 396 | isexe@^2.0.0: 397 | version "2.0.0" 398 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 399 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 400 | 401 | js-yaml@3.14.0: 402 | version "3.14.0" 403 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" 404 | integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== 405 | dependencies: 406 | argparse "^1.0.7" 407 | esprima "^4.0.0" 408 | 409 | locate-path@^3.0.0: 410 | version "3.0.0" 411 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 412 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== 413 | dependencies: 414 | p-locate "^3.0.0" 415 | path-exists "^3.0.0" 416 | 417 | locate-path@^6.0.0: 418 | version "6.0.0" 419 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" 420 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 421 | dependencies: 422 | p-locate "^5.0.0" 423 | 424 | lodash@^4.17.20: 425 | version "4.17.20" 426 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" 427 | integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== 428 | 429 | log-symbols@4.0.0: 430 | version "4.0.0" 431 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" 432 | integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== 433 | dependencies: 434 | chalk "^4.0.0" 435 | 436 | make-error@^1.1.1: 437 | version "1.3.6" 438 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" 439 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== 440 | 441 | minimatch@3.0.4, minimatch@^3.0.4: 442 | version "3.0.4" 443 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 444 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 445 | dependencies: 446 | brace-expansion "^1.1.7" 447 | 448 | mocha@^8.2.1: 449 | version "8.2.1" 450 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.2.1.tgz#f2fa68817ed0e53343d989df65ccd358bc3a4b39" 451 | integrity sha512-cuLBVfyFfFqbNR0uUKbDGXKGk+UDFe6aR4os78XIrMQpZl/nv7JYHcvP5MFIAb374b2zFXsdgEGwmzMtP0Xg8w== 452 | dependencies: 453 | "@ungap/promise-all-settled" "1.1.2" 454 | ansi-colors "4.1.1" 455 | browser-stdout "1.3.1" 456 | chokidar "3.4.3" 457 | debug "4.2.0" 458 | diff "4.0.2" 459 | escape-string-regexp "4.0.0" 460 | find-up "5.0.0" 461 | glob "7.1.6" 462 | growl "1.10.5" 463 | he "1.2.0" 464 | js-yaml "3.14.0" 465 | log-symbols "4.0.0" 466 | minimatch "3.0.4" 467 | ms "2.1.2" 468 | nanoid "3.1.12" 469 | serialize-javascript "5.0.1" 470 | strip-json-comments "3.1.1" 471 | supports-color "7.2.0" 472 | which "2.0.2" 473 | wide-align "1.1.3" 474 | workerpool "6.0.2" 475 | yargs "13.3.2" 476 | yargs-parser "13.1.2" 477 | yargs-unparser "2.0.0" 478 | 479 | ms@2.0.0: 480 | version "2.0.0" 481 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 482 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 483 | 484 | ms@2.1.2: 485 | version "2.1.2" 486 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 487 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 488 | 489 | nanoid@3.1.12: 490 | version "3.1.12" 491 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.12.tgz#6f7736c62e8d39421601e4a0c77623a97ea69654" 492 | integrity sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A== 493 | 494 | normalize-path@^3.0.0, normalize-path@~3.0.0: 495 | version "3.0.0" 496 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 497 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 498 | 499 | once@^1.3.0: 500 | version "1.4.0" 501 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 502 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 503 | dependencies: 504 | wrappy "1" 505 | 506 | p-limit@^2.0.0: 507 | version "2.3.0" 508 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" 509 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== 510 | dependencies: 511 | p-try "^2.0.0" 512 | 513 | p-limit@^3.0.2: 514 | version "3.1.0" 515 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" 516 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 517 | dependencies: 518 | yocto-queue "^0.1.0" 519 | 520 | p-locate@^3.0.0: 521 | version "3.0.0" 522 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 523 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== 524 | dependencies: 525 | p-limit "^2.0.0" 526 | 527 | p-locate@^5.0.0: 528 | version "5.0.0" 529 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" 530 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 531 | dependencies: 532 | p-limit "^3.0.2" 533 | 534 | p-try@^2.0.0: 535 | version "2.2.0" 536 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 537 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 538 | 539 | path-exists@^3.0.0: 540 | version "3.0.0" 541 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 542 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 543 | 544 | path-exists@^4.0.0: 545 | version "4.0.0" 546 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 547 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 548 | 549 | path-is-absolute@^1.0.0: 550 | version "1.0.1" 551 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 552 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 553 | 554 | pathval@^1.1.0: 555 | version "1.1.0" 556 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" 557 | integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= 558 | 559 | picomatch@^2.0.4, picomatch@^2.2.1: 560 | version "2.2.2" 561 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" 562 | integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== 563 | 564 | prettier@^2.2.1: 565 | version "2.2.1" 566 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" 567 | integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== 568 | 569 | randombytes@^2.1.0: 570 | version "2.1.0" 571 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" 572 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 573 | dependencies: 574 | safe-buffer "^5.1.0" 575 | 576 | readdirp@~3.5.0: 577 | version "3.5.0" 578 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" 579 | integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== 580 | dependencies: 581 | picomatch "^2.2.1" 582 | 583 | require-directory@^2.1.1: 584 | version "2.1.1" 585 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 586 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 587 | 588 | require-main-filename@^2.0.0: 589 | version "2.0.0" 590 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" 591 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== 592 | 593 | safe-buffer@^5.1.0: 594 | version "5.2.1" 595 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 596 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 597 | 598 | serialize-javascript@5.0.1: 599 | version "5.0.1" 600 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" 601 | integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== 602 | dependencies: 603 | randombytes "^2.1.0" 604 | 605 | set-blocking@^2.0.0: 606 | version "2.0.0" 607 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 608 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 609 | 610 | source-map-support@^0.5.17: 611 | version "0.5.19" 612 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" 613 | integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== 614 | dependencies: 615 | buffer-from "^1.0.0" 616 | source-map "^0.6.0" 617 | 618 | source-map@^0.6.0: 619 | version "0.6.1" 620 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 621 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 622 | 623 | sprintf-js@~1.0.2: 624 | version "1.0.3" 625 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 626 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 627 | 628 | stream-parser@^0.3.1: 629 | version "0.3.1" 630 | resolved "https://registry.yarnpkg.com/stream-parser/-/stream-parser-0.3.1.tgz#1618548694420021a1182ff0af1911c129761773" 631 | integrity sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M= 632 | dependencies: 633 | debug "2" 634 | 635 | "string-width@^1.0.2 || 2": 636 | version "2.1.1" 637 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 638 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 639 | dependencies: 640 | is-fullwidth-code-point "^2.0.0" 641 | strip-ansi "^4.0.0" 642 | 643 | string-width@^3.0.0, string-width@^3.1.0: 644 | version "3.1.0" 645 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 646 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 647 | dependencies: 648 | emoji-regex "^7.0.1" 649 | is-fullwidth-code-point "^2.0.0" 650 | strip-ansi "^5.1.0" 651 | 652 | strip-ansi@^4.0.0: 653 | version "4.0.0" 654 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 655 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 656 | dependencies: 657 | ansi-regex "^3.0.0" 658 | 659 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: 660 | version "5.2.0" 661 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 662 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 663 | dependencies: 664 | ansi-regex "^4.1.0" 665 | 666 | strip-json-comments@3.1.1: 667 | version "3.1.1" 668 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 669 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 670 | 671 | supports-color@7.2.0, supports-color@^7.1.0: 672 | version "7.2.0" 673 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 674 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 675 | dependencies: 676 | has-flag "^4.0.0" 677 | 678 | to-regex-range@^5.0.1: 679 | version "5.0.1" 680 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 681 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 682 | dependencies: 683 | is-number "^7.0.0" 684 | 685 | ts-node@^9.1.1: 686 | version "9.1.1" 687 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" 688 | integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg== 689 | dependencies: 690 | arg "^4.1.0" 691 | create-require "^1.1.0" 692 | diff "^4.0.1" 693 | make-error "^1.1.1" 694 | source-map-support "^0.5.17" 695 | yn "3.1.1" 696 | 697 | type-detect@^4.0.0, type-detect@^4.0.5: 698 | version "4.0.8" 699 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 700 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 701 | 702 | typescript@^4.1.3: 703 | version "4.1.3" 704 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" 705 | integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== 706 | 707 | which-module@^2.0.0: 708 | version "2.0.0" 709 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" 710 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= 711 | 712 | which@2.0.2: 713 | version "2.0.2" 714 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 715 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 716 | dependencies: 717 | isexe "^2.0.0" 718 | 719 | wide-align@1.1.3: 720 | version "1.1.3" 721 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 722 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 723 | dependencies: 724 | string-width "^1.0.2 || 2" 725 | 726 | workerpool@6.0.2: 727 | version "6.0.2" 728 | resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.0.2.tgz#e241b43d8d033f1beb52c7851069456039d1d438" 729 | integrity sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q== 730 | 731 | wrap-ansi@^5.1.0: 732 | version "5.1.0" 733 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" 734 | integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== 735 | dependencies: 736 | ansi-styles "^3.2.0" 737 | string-width "^3.0.0" 738 | strip-ansi "^5.0.0" 739 | 740 | wrappy@1: 741 | version "1.0.2" 742 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 743 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 744 | 745 | y18n@^4.0.0: 746 | version "4.0.0" 747 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" 748 | integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== 749 | 750 | yargs-parser@13.1.2, yargs-parser@^13.1.2: 751 | version "13.1.2" 752 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" 753 | integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== 754 | dependencies: 755 | camelcase "^5.0.0" 756 | decamelize "^1.2.0" 757 | 758 | yargs-unparser@2.0.0: 759 | version "2.0.0" 760 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" 761 | integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== 762 | dependencies: 763 | camelcase "^6.0.0" 764 | decamelize "^4.0.0" 765 | flat "^5.0.2" 766 | is-plain-obj "^2.1.0" 767 | 768 | yargs@13.3.2: 769 | version "13.3.2" 770 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" 771 | integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== 772 | dependencies: 773 | cliui "^5.0.0" 774 | find-up "^3.0.0" 775 | get-caller-file "^2.0.1" 776 | require-directory "^2.1.1" 777 | require-main-filename "^2.0.0" 778 | set-blocking "^2.0.0" 779 | string-width "^3.0.0" 780 | which-module "^2.0.0" 781 | y18n "^4.0.0" 782 | yargs-parser "^13.1.2" 783 | 784 | yn@3.1.1: 785 | version "3.1.1" 786 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" 787 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== 788 | 789 | yocto-queue@^0.1.0: 790 | version "0.1.0" 791 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" 792 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 793 | --------------------------------------------------------------------------------