Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/reduce bundle size #453

Open
wants to merge 8 commits into
base: v1-migration
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions lerna.json

This file was deleted.

1,289 changes: 603 additions & 686 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"@types/ua-parser-js": "^0.7.39",
"buffer": "^6.0.3",
"events": "^3.3.0",
"joi": "^17.12.0",
"js-base64": "^3.7.7",
"js-logger": "^1.6.1",
"jsdoc-i18n-plugin": "^0.0.3",
Expand Down
4 changes: 2 additions & 2 deletions packages/millicast-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"realtime",
"streaming"
],
"main": "./index.js",
"module": "./index.mjs",
"main": "./millicast.mjs",
"module": "./millicast.mjs",
"typings": "./index.d.ts",
"files": [
"dist",
Expand Down
23 changes: 2 additions & 21 deletions packages/millicast-sdk/src/Publish.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import jwtDecode from 'jwt-decode'
import reemit from 're-emitter'
import { atob } from 'js-base64'
import joi from 'joi'
import Logger from './Logger'
import BaseWebRTC from './utils/BaseWebRTC'
import Signaling, { signalingEvents } from './Signaling'
Expand All @@ -16,6 +15,7 @@ import { DecodedJWT, ReconnectData } from './types/BaseWebRTC.types'
import { SEIUserUnregisteredData } from './types/View.types'
import { SignalingPublishOptions } from './types/Signaling.types'
import { VideoCodec } from './types/Codecs.types'
import { validatePublishConnectOptions } from './utils/Validators'

const logger = Logger.get('Publish')

Expand Down Expand Up @@ -114,26 +114,7 @@ export default class Publish extends BaseWebRTC {
* }
*/
override async connect(options: PublishConnectOptions = connectOptions): Promise<void> {
const schema = joi.object({
sourceId: joi.string(),
stereo: joi.boolean(),
dtx: joi.boolean(),
absCaptureTime: joi.boolean(),
dependencyDescriptor: joi.boolean(),
mediaStream: joi.alternatives().try(joi.array().items(joi.object()), joi.object()),
bandwidth: joi.number(),
metadata: joi.boolean(),
disableVideo: joi.boolean(),
disableAudio: joi.boolean(),
codec: joi.string().valid(...Object.values(VideoCodec)),
simulcast: joi.boolean(),
scalabilityMode: joi.string(),
peerConfig: joi.object(),
record: joi.boolean(),
events: joi.array().items(joi.string().valid('active', 'inactive', 'viewercount')),
priority: joi.number(),
})
const { error, value } = schema.validate(options)
const { error, value } = validatePublishConnectOptions(options)
if (error) logger.warn(error, value)
this.options = {
...connectOptions,
Expand Down
2 changes: 1 addition & 1 deletion packages/millicast-sdk/src/types/Publish.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export type PublishConnectOptions = {
/**
* - Specify which events will be delivered by the server (any of "active" | "inactive" | "viewercount").*
*/
events?: PublishServerEvent
events?: PublishServerEvent[]
/**
* - When multiple ingest streams are provided by the customer, add the ability to specify a priority between all ingest streams. Decimal integer between the range [-2^31, +2^31 - 1]. For more information, visit [our documentation](https://docs.dolby.io/streaming-apis/docs/backup-publishing).
*/
Expand Down
105 changes: 105 additions & 0 deletions packages/millicast-sdk/src/utils/Validators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { VideoCodec } from '../types/Codecs.types'
import { PublishConnectOptions } from '../types/Publish.types'

class ValidationError extends Error {
messages: string[]

constructor(messages: string[]) {
super('Validation Failed')
this.name = 'ValidationError'
this.messages = messages
}
}

const isString = (value: unknown) => typeof value === 'string'

const isNumber = (value: unknown) => typeof value === 'number'

const isBoolean = (value: unknown) => typeof value === 'boolean'

const isArray = (value: unknown) => Array.isArray(value)

const isObject = (value: unknown) => typeof value === 'object' && value !== null && !Array.isArray(value)

const isSupporedVideoCodec = (value: unknown): value is VideoCodec =>
Object.values(VideoCodec).includes(value as VideoCodec)

export function validatePublishConnectOptions(obj: any): {

Check warning on line 27 in packages/millicast-sdk/src/utils/Validators.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
error?: ValidationError
value: PublishConnectOptions
} {
const errorMessages: string[] = []
let error: ValidationError | undefined

if (!isObject(obj)) {
return { error: new ValidationError([`Publish Connection Options must be an object`]), value: obj }
}

if (obj.sourceId && !isString(obj.sourceId)) {
errorMessages.push(`Invalid sourceId: ${obj.sourceId}`)
}

if (obj.stereo in obj && !isBoolean(obj.stereo)) {
errorMessages.push(`Invalid stereo: ${obj.stereo}`)
}
if (obj.dtx && !isBoolean(obj.dtx)) {
errorMessages.push(`Invalid dtx: ${obj.dtx}`)
}
if (obj.absCaptureTime && !isBoolean(obj.absCaptureTime)) {
errorMessages.push(`Invalid absCaptureTime: ${obj.absCaptureTime}`)
}
if (obj.dependencyDescriptor && !isBoolean(obj.dependencyDescriptor)) {
errorMessages.push(`Invalid dependencyDescriptor: ${obj.dependencyDescriptor}`)
}
if (
obj.mediaStream !== undefined &&
!isObject(obj.mediaStream) &&
!(isArray(obj.mediaStream) && obj.mediaStream.every(isObject))
) {
errorMessages.push(`Invalid mediaStream: ${obj.mediaStream}`)
}
if (obj.bandwidth && !isNumber(obj.bandwidth)) {
errorMessages.push(`Invalid bandwidth: ${obj.bandwidth}`)
}
if (obj.metadata && !isBoolean(obj.metadata)) {
errorMessages.push(`Invalid metadata: ${obj.metadata}`)
}
if (obj.disableVideo && !isBoolean(obj.disableVideo)) {
errorMessages.push(`Invalid disableVideo: ${obj.disableVideo}`)
}
if (obj.disableAudio && !isBoolean(obj.disableAudio)) {
errorMessages.push(`Invalid disableAudio: ${obj.disableAudio}`)
}
if (obj.codec !== undefined && !isSupporedVideoCodec(obj.codec)) {
errorMessages.push(`Invalid codec: ${obj.codec}`)
}
if (obj.simulcast && !isBoolean(obj.simulcast)) {
errorMessages.push(`Invalid simulcast: ${obj.simulcast}`)
}
if (obj.scalabilityMode && !isString(obj.scalabilityMode)) {
errorMessages.push(`Invalid scalabilityMode: ${obj.scalabilityMode}`)
}
if (obj.peerConfig && !isObject(obj.peerConfig)) {
errorMessages.push(`Invalid peerConfig: ${obj.peerConfig}`)
}
if (obj.record && !isBoolean(obj.record)) {
errorMessages.push(`Invalid record: ${obj.record}`)
}
if (
obj.events &&
(!isArray(obj.events) ||
!obj.events.every(
(event: unknown) => isString(event) && ['active', 'inactive', 'viewercount'].includes(event)
))
) {
errorMessages.push(`Invalid events: ${obj.events}`)
}
if (obj.priority && !isNumber(obj.priority)) {
errorMessages.push(`Invalid priority: ${obj.priority}`)
}

if (errorMessages.length) {
error = new ValidationError(errorMessages)
}
return { error: error, value: obj }
}
152 changes: 152 additions & 0 deletions packages/millicast-sdk/tests/unit/Validator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { VideoCodec } from '../../src/types/Codecs.types'
import { validatePublishConnectOptions } from '../../src/utils/Validators'

describe('Validator: "validatePublishConnectOptions"', () => {
let validPublishConnectionOptions: any

Check warning on line 5 in packages/millicast-sdk/tests/unit/Validator.test.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
beforeEach(() => {
validPublishConnectionOptions = {
bandwidth: 0,
sourceId: 'sourceId',
codec: VideoCodec.H264,
events: ['viewercount'],
metadata: false,
simulcast: false,
disableVideo: false,
disableAudio: false,
peerConfig: { autoInitStats: true, statsIntervalMs: 5000 },
mediaStream: {} as MediaStream,
}
})
it('should return error for non object arguments', () => {
const falseValidate = validatePublishConnectOptions(false)
expect(falseValidate.error?.messages[0]).toBe('Publish Connection Options must be an object')
const undefinedValidate = validatePublishConnectOptions(undefined)
expect(undefinedValidate.error?.messages[0]).toBe('Publish Connection Options must be an object')
const nullVaidate = validatePublishConnectOptions(null)
expect(nullVaidate.error?.messages[0]).toBe('Publish Connection Options must be an object')
const arrayVaidate = validatePublishConnectOptions([])
expect(arrayVaidate.error?.messages[0]).toBe('Publish Connection Options must be an object')
})
it('should validate for empty object', () => {
const { error } = validatePublishConnectOptions({})
expect(error).toBeUndefined()
})
it('should not return error for valid options', () => {
const { error } = validatePublishConnectOptions(validPublishConnectionOptions)
expect(error).toBeUndefined()
})
describe('should return error for invalid', () => {
it('bandwidth', () => {
validPublishConnectionOptions.bandwidth = true
const { error } = validatePublishConnectOptions(validPublishConnectionOptions)
expect(error?.messages[0]).toContain('Invalid bandwidth')
})
it('sourceId', () => {
validPublishConnectionOptions.sourceId = 2
const { error } = validatePublishConnectOptions(validPublishConnectionOptions)
expect(error?.messages[0]).toContain('Invalid sourceId')
})
it('metadata', () => {
validPublishConnectionOptions.metadata = {}
const { error } = validatePublishConnectOptions(validPublishConnectionOptions)
expect(error?.messages[0]).toContain('Invalid metadata')
})
it('peerConfig', () => {
validPublishConnectionOptions.peerConfig = 2
const { error } = validatePublishConnectOptions(validPublishConnectionOptions)
expect(error?.messages[0]).toContain('Invalid peerConfig')
})
it('videoCodec', () => {
validPublishConnectionOptions.codec = 'random string'
const randomStringValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(randomStringValidation.error?.messages[0]).toContain('Invalid codec')
validPublishConnectionOptions.codec = ''
const emptyStringValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(emptyStringValidation.error?.messages[0]).toContain('Invalid codec')
})
it('mediaStream', () => {
validPublishConnectionOptions.mediaStream = 'random string'
const randomStringValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(randomStringValidation.error?.messages[0]).toContain('Invalid mediaStream')
validPublishConnectionOptions.mediaStream = null
const nullValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(nullValidation.error?.messages[0]).toContain('Invalid mediaStream')
validPublishConnectionOptions.mediaStream = [1, true, 'string']
const invalidArrayValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(invalidArrayValidation.error?.messages[0]).toContain('Invalid mediaStream')
})
it('events', () => {
validPublishConnectionOptions.events = 'active'
const stringEventsValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(stringEventsValidation.error?.messages[0]).toContain('Invalid events')
validPublishConnectionOptions.events = ['active', 'fake_event']
const fakeEventValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(fakeEventValidation.error?.messages[0]).toContain('Invalid events')
validPublishConnectionOptions.events = [1, 2, 3]
const improperEventTypeValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(improperEventTypeValidation.error?.messages[0]).toContain('Invalid events')
})
})
describe('should not return error for valid', () => {
it('videoCodec', () => {
validPublishConnectionOptions.codec = 'vp8'
const vp8Validation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(vp8Validation.error).toBeUndefined()
validPublishConnectionOptions.codec = 'vp9'
const vp9Validation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(vp9Validation.error).toBeUndefined()
validPublishConnectionOptions.codec = 'av1'
const av1Validation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(av1Validation.error).toBeUndefined()
validPublishConnectionOptions.codec = 'h264'
const h264Validation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(h264Validation.error).toBeUndefined()
validPublishConnectionOptions.codec = 'h265'
const h265Validation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(h265Validation.error).toBeUndefined()
})
it('mediaStream', () => {
validPublishConnectionOptions.mediaStream = {}
const emptyObjValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(emptyObjValidation.error).toBeUndefined()
validPublishConnectionOptions.mediaStream = {
id: '12345',
active: true,
addTrack: jest.fn,
removeTrack: jest.fn,
}
const mediaStreamValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(mediaStreamValidation.error).toBeUndefined()
validPublishConnectionOptions.mediaStream = []
const emptyArrayValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(emptyArrayValidation.error).toBeUndefined()
validPublishConnectionOptions.mediaStream = [
{
id: '12345',
active: true,
addTrack: jest.fn,
removeTrack: jest.fn,
},
{
id: '67890',
active: false,
addTrack: jest.fn,
removeTrack: jest.fn,
},
]
const arrayObjsValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(arrayObjsValidation.error).toBeUndefined()
})
it('events', () => {
validPublishConnectionOptions.events = []
const emptyEventsValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(emptyEventsValidation.error).toBeUndefined()
validPublishConnectionOptions.events = ['active', 'inactive', 'viewercount']
const properEventsValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(properEventsValidation.error).toBeUndefined()
validPublishConnectionOptions.events = ['active']
const singleEventValidation = validatePublishConnectOptions(validPublishConnectionOptions)
expect(singleEventValidation.error).toBeUndefined()
})
})
})
2 changes: 1 addition & 1 deletion packages/millicast-sdk/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default defineConfig({
fileName: 'millicast',
// Change this to the formats you want to support.
// Don't forget to update your package.json as well.
formats: ['es', 'cjs', 'umd'],
formats: ['es', 'umd'],
},
rollupOptions: {
// External packages that should not be bundled into your library.
Expand Down