diff --git a/package-lock.json b/package-lock.json
index e51b2fea..72ae2321 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,6 +17,7 @@
                 "@rollup/plugin-replace": "^6.0.1",
                 "@types/jest": "^29.5.12",
                 "@types/node": "^20.6.1",
+                "@types/webrtc": "^0.0.44",
                 "@typescript-eslint/eslint-plugin": "^7.17.0",
                 "@typescript-eslint/parser": "^7.17.0",
                 "cmake-js": "^7.3.0",
@@ -1716,6 +1717,13 @@
             "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
             "dev": true
         },
+        "node_modules/@types/webrtc": {
+            "version": "0.0.44",
+            "resolved": "https://registry.npmjs.org/@types/webrtc/-/webrtc-0.0.44.tgz",
+            "integrity": "sha512-4BJZdzrApNFeuXgucyqs24k69f7oti3wUcGEbFbaV08QBh7yEe3tnRRuYXlyXJNXiumpZujiZqUZZ2/gMSeO0g==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/@types/yargs": {
             "version": "17.0.24",
             "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
diff --git a/package.json b/package.json
index 0ba72fa6..c9303a32 100644
--- a/package.json
+++ b/package.json
@@ -79,6 +79,7 @@
         "@rollup/plugin-replace": "^6.0.1",
         "@types/jest": "^29.5.12",
         "@types/node": "^20.6.1",
+        "@types/webrtc": "^0.0.44",
         "@typescript-eslint/eslint-plugin": "^7.17.0",
         "@typescript-eslint/parser": "^7.17.0",
         "cmake-js": "^7.3.0",
@@ -104,4 +105,4 @@
     "dependencies": {
         "prebuild-install": "^7.1.2"
     }
-}
+}
\ No newline at end of file
diff --git a/src/polyfill/Events.ts b/src/polyfill/Events.ts
index d7ac9f88..8400114a 100644
--- a/src/polyfill/Events.ts
+++ b/src/polyfill/Events.ts
@@ -14,20 +14,63 @@ export class RTCPeerConnectionIceEvent extends Event implements globalThis.RTCPe
     get candidate(): RTCIceCandidate {
         return this.#candidate;
     }
+
+    get url (): string {
+        return '' // TODO ?
+    }
 }
 
 export class RTCDataChannelEvent extends Event implements globalThis.RTCDataChannelEvent {
     #channel: RTCDataChannel;
 
-    constructor(type: string, eventInitDict: globalThis.RTCDataChannelEventInit) {
-        super(type);
+    // type is defined as a consturctor, but always overwritten, interesting spec
+    // eslint-disable-next-line @typescript-eslint/no-unused-vars
+    constructor(_type: string = 'datachannel', init: globalThis.RTCDataChannelEventInit) {
+        if (arguments.length === 0) throw new TypeError(`Failed to construct 'RTCDataChannelEvent': 2 arguments required, but only ${arguments.length} present.`)
+        if (typeof init !== 'object') throw new TypeError("Failed to construct 'RTCDataChannelEvent': The provided value is not of type 'RTCDataChannelEventInit'.")
+        if (!init.channel) throw new TypeError("Failed to construct 'RTCDataChannelEvent': Failed to read the 'channel' property from 'RTCDataChannelEventInit': Required member is undefined.")
+        if (init.channel.constructor !== RTCDataChannel) throw new TypeError("Failed to construct 'RTCDataChannelEvent': Failed to read the 'channel' property from 'RTCDataChannelEventInit': Failed to convert value to 'RTCDataChannel'.")
+        super('datachannel')
 
-        if (type && !eventInitDict.channel) throw new TypeError('channel member is required');
-
-        this.#channel = eventInitDict?.channel as RTCDataChannel;
+        this.#channel = init.channel;
     }
 
     get channel(): RTCDataChannel {
         return this.#channel;
     }
 }
+
+export class RTCErrorEvent extends Event implements globalThis.RTCErrorEvent {
+    #error: RTCError
+    constructor (type: string, init: globalThis.RTCErrorEventInit) {
+        if (arguments.length < 2) throw new TypeError(`Failed to construct 'RTCErrorEvent': 2 arguments required, but only ${arguments.length} present.`)
+        if (typeof init !== 'object') throw new TypeError("Failed to construct 'RTCErrorEvent': The provided value is not of type 'RTCErrorEventInit'.")
+        if (!init.error) throw new TypeError("Failed to construct 'RTCErrorEvent': Failed to read the 'error' property from 'RTCErrorEventInit': Required member is undefined.")
+        if (init.error.constructor !== RTCError) throw new TypeError("Failed to construct 'RTCErrorEvent': Failed to read the 'error' property from 'RTCErrorEventInit': Failed to convert value to 'RTCError'.")
+        super(type || 'error')
+        this.#error = init.error
+    }
+
+    get error (): RTCError {
+        return this.#error
+    }
+}
+
+export class MediaStreamTrackEvent extends Event implements globalThis.MediaStreamTrackEvent {
+    #track: MediaStreamTrack
+
+    constructor (type, init) {
+        if (arguments.length === 0) throw new TypeError(`Failed to construct 'MediaStreamTrackEvent': 2 arguments required, but only ${arguments.length} present.`)
+        if (typeof init !== 'object') throw new TypeError("Failed to construct 'MediaStreamTrackEvent': The provided value is not of type 'MediaStreamTrackEventInit'.")
+        if (!init.track) throw new TypeError("Failed to construct 'MediaStreamTrackEvent': Failed to read the 'track' property from 'MediaStreamTrackEventInit': Required member is undefined.")
+        if (init.track.constructor !== MediaStreamTrack) throw new TypeError("Failed to construct 'MediaStreamTrackEvent': Failed to read the 'channel' property from 'MediaStreamTrackEventInit': Failed to convert value to 'RTCDataChannel'.")
+
+        super(type)
+
+        this.#track = init.track
+    }
+
+    get track (): MediaStreamTrack {
+        return this.#track
+    }
+}
diff --git a/src/polyfill/RTCCertificate.ts b/src/polyfill/RTCCertificate.ts
index 4069837e..9a4651bb 100644
--- a/src/polyfill/RTCCertificate.ts
+++ b/src/polyfill/RTCCertificate.ts
@@ -14,4 +14,8 @@ export default class RTCCertificate implements globalThis.RTCCertificate {
     getFingerprints(): globalThis.RTCDtlsFingerprint[] {
         return this.#fingerprints;
     }
+
+    getAlgorithm (): string {
+        return ''
+    }
 }
diff --git a/src/polyfill/RTCDataChannel.ts b/src/polyfill/RTCDataChannel.ts
index 3a097e92..ce47a83a 100644
--- a/src/polyfill/RTCDataChannel.ts
+++ b/src/polyfill/RTCDataChannel.ts
@@ -1,38 +1,37 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
 import * as exceptions from './Exception';
 import { DataChannel } from '../lib/index';
+import RTCPeerConnection from './RTCPeerConnection';
+import { RTCErrorEvent } from './Events';
 
 export default class RTCDataChannel extends EventTarget implements globalThis.RTCDataChannel {
     #dataChannel: DataChannel;
     #readyState: RTCDataChannelState;
-    #bufferedAmountLowThreshold: number;
-    #binaryType: BinaryType;
+    #bufferedAmountLowThreshold: number = 0;
+    #binaryType: BinaryType = 'blob';
     #maxPacketLifeTime: number | null;
     #maxRetransmits: number | null;
     #negotiated: boolean;
     #ordered: boolean;
-
-    #closeRequested = false;
+    #pc: RTCPeerConnection;
 
     // events
-    onbufferedamountlow: ((this: RTCDataChannel, ev: Event) => any) | null;
-    onclose: ((this: RTCDataChannel, ev: Event) => any) | null;
-    onclosing: ((this: RTCDataChannel, ev: Event) => any) | null;
-    onerror: ((this: RTCDataChannel, ev: Event) => any) | null;
-    onmessage: ((this: RTCDataChannel, ev: MessageEvent) => any) | null;
-    onopen: ((this: RTCDataChannel, ev: Event) => any) | null;
-
-    constructor(dataChannel: DataChannel, opts: globalThis.RTCDataChannelInit = {}) {
+    onbufferedamountlow: globalThis.RTCDataChannel['onbufferedamountlow'];
+    onclose: globalThis.RTCDataChannel['onclose'];
+    onclosing: globalThis.RTCDataChannel['onclosing'];
+    onerror: globalThis.RTCDataChannel['onerror'];
+    onmessage: globalThis.RTCDataChannel['onmessage'];
+    onopen: globalThis.RTCDataChannel['onopen']
+
+    constructor(dataChannel: DataChannel, opts: globalThis.RTCDataChannelInit = {}, pc: RTCPeerConnection) {
         super();
 
         this.#dataChannel = dataChannel;
-        this.#binaryType = 'blob';
         this.#readyState = this.#dataChannel.isOpen() ? 'open' : 'connecting';
-        this.#bufferedAmountLowThreshold = 0;
-        this.#maxPacketLifeTime = opts.maxPacketLifeTime || null;
-        this.#maxRetransmits = opts.maxRetransmits || null;
-        this.#negotiated = opts.negotiated || false;
-        this.#ordered = opts.ordered || true;
+        this.#maxPacketLifeTime = opts.maxPacketLifeTime ?? null;
+        this.#maxRetransmits = opts.maxRetransmits ?? null;
+        this.#negotiated = opts.negotiated ?? false;
+        this.#ordered = opts.ordered ?? true;
+        this.#pc = pc
 
         // forward dataChannel events
         this.#dataChannel.onOpen(() => {
@@ -40,18 +39,22 @@ export default class RTCDataChannel extends EventTarget implements globalThis.RT
             this.dispatchEvent(new Event('open', {}));
         });
 
-        this.#dataChannel.onClosed(() => {
-            // Simulate closing event
-            if (!this.#closeRequested) {
-                this.#readyState = 'closing';
-                this.dispatchEvent(new Event('closing'));
-            }
 
-            setImmediate(() => {
-                this.#readyState = 'closed';
-                this.dispatchEvent(new Event('close'));
-            });
-        });
+    // we need updated connectionstate, so this is delayed by a single event loop tick
+    // this is fucked and wonky, needs to be made better
+    this.#dataChannel.onClosed(() => setTimeout(() => {
+        if (this.#readyState !== 'closed') {
+          // this should be 'disconnected' but ldc doesn't support that
+        if (this.#pc.connectionState === 'closed') {
+            // if the remote connection suddently closes without closing dc first, throw this weird error
+            this.dispatchEvent(new RTCErrorEvent('error', { error: new RTCError({ errorDetail: 'sctp-failure', sctpCauseCode: 12 }, 'User-Initiated Abort, reason=Close called') }))
+        }
+        this.#readyState = 'closing'
+        this.dispatchEvent(new Event('closing'))
+        this.#readyState = 'closed'
+        }
+        this.dispatchEvent(new Event('close'))
+    }))
 
         this.#dataChannel.onError((msg) => {
             this.dispatchEvent(
@@ -70,16 +73,17 @@ export default class RTCDataChannel extends EventTarget implements globalThis.RT
             this.dispatchEvent(new Event('bufferedamountlow'));
         });
 
-        this.#dataChannel.onMessage((data) => {
-            if (ArrayBuffer.isView(data)) {
-                if (this.binaryType == 'arraybuffer')
-                    data = data.buffer;
-                else
-                    data = Buffer.from(data.buffer);
+        this.#dataChannel.onMessage(message => {
+            let data: Blob | ArrayBufferLike | string
+            if (!ArrayBuffer.isView(message)) {
+                data = message
+            } else if (this.#binaryType === 'blob') {
+                data = new Blob([message])
+            } else {
+                data = message.buffer
             }
-
-            this.dispatchEvent(new MessageEvent('message', { data }));
-        });
+            this.dispatchEvent(new MessageEvent('message', { data }))
+        })
 
         // forward events to properties
         this.addEventListener('message', (e) => {
@@ -89,7 +93,7 @@ export default class RTCDataChannel extends EventTarget implements globalThis.RT
             if (this.onbufferedamountlow) this.onbufferedamountlow(e);
         });
         this.addEventListener('error', (e) => {
-            if (this.onerror) this.onerror(e);
+            if (this.onerror) this.onerror(e as RTCErrorEvent);
         });
         this.addEventListener('close', (e) => {
             if (this.onclose) this.onclose(e);
@@ -162,7 +166,11 @@ export default class RTCDataChannel extends EventTarget implements globalThis.RT
         return this.#readyState;
     }
 
-    send(data): void {
+    get maxMessageSize (): number {
+        return this.#dataChannel.maxMessageSize()
+    }
+
+    send(data: string | Blob | ArrayBuffer | ArrayBufferView | Buffer): void {
         if (this.#readyState !== 'open') {
             throw new exceptions.InvalidStateError(
                 "Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel.readyState is not 'open'",
@@ -171,26 +179,29 @@ export default class RTCDataChannel extends EventTarget implements globalThis.RT
 
         // Needs network error, type error implemented
         if (typeof data === 'string') {
+            if (data.length > this.#dataChannel.maxMessageSize()) throw new TypeError('Max message size exceeded.')
             this.#dataChannel.sendMessage(data);
-        } else if (data instanceof Blob) {
+        } else if ('arrayBuffer' in data) {
+            if (data.size > this.#dataChannel.maxMessageSize()) throw new TypeError('Max message size exceeded.')
             data.arrayBuffer().then((ab) => {
-                if (process?.versions?.bun) {
-                    this.#dataChannel.sendMessageBinary(Buffer.from(ab));
-                } else {
-                    this.#dataChannel.sendMessageBinary(new Uint8Array(ab));
-                }
+                this.#dataChannel.sendMessageBinary( process?.versions?.bun ? Buffer.from(ab) : new Uint8Array(ab));
             });
         } else {
-            if (process?.versions?.bun) {
-                this.#dataChannel.sendMessageBinary(Buffer.from(data));
-            } else {
-                this.#dataChannel.sendMessageBinary(new Uint8Array(data));
-            }
+            if (data.byteLength > this.#dataChannel.maxMessageSize()) throw new TypeError('Max message size exceeded.')
+            this.#dataChannel.sendMessageBinary( process?.versions?.bun ? Buffer.from(data as ArrayBuffer) : new Uint8Array(data as ArrayBuffer));
         }
     }
 
-    close(): void {
-        this.#closeRequested = true;
-        this.#dataChannel.close();
+    close (): void {
+        this.#readyState = 'closed'
+        setTimeout(() => {
+            if (this.#pc.connectionState === 'closed') {
+                // if the remote connection suddently closes without closing dc first, throw this weird error
+                // can this be done better?
+                this.dispatchEvent(new RTCErrorEvent('error', { error: new RTCError({ errorDetail: 'sctp-failure', sctpCauseCode: 12 }, 'User-Initiated Abort, reason=Close called') }))
+            }
+        })
+
+        this.#dataChannel.close()
     }
 }
diff --git a/src/polyfill/RTCDtlsTransport.ts b/src/polyfill/RTCDtlsTransport.ts
index 34590eb6..0c4969f4 100644
--- a/src/polyfill/RTCDtlsTransport.ts
+++ b/src/polyfill/RTCDtlsTransport.ts
@@ -1,4 +1,3 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
 import RTCIceTransport from './RTCIceTransport';
 import RTCPeerConnection from './RTCPeerConnection';
 
@@ -6,23 +5,20 @@ export default class RTCDtlsTransport extends EventTarget implements globalThis.
     #pc: RTCPeerConnection = null;
     #iceTransport = null;
 
-    onstatechange: ((this: RTCDtlsTransport, ev: Event) => any) | null = null;
-    onerror: ((this: RTCDtlsTransport, ev: Event) => any) | null = null;
+    onstatechange: globalThis.RTCDtlsTransport['onstatechange'];
+    onerror: globalThis.RTCDtlsTransport['onstatechange'];
 
-    constructor(init: { pc: RTCPeerConnection, extraFunctions }) {
+    constructor({ pc }: { pc: RTCPeerConnection }) {
         super();
-        this.#pc = init.pc;
+        this.#pc = pc;
 
-        this.#iceTransport = new RTCIceTransport({ pc: init.pc, extraFunctions: init.extraFunctions });
+        this.#iceTransport = new RTCIceTransport({ pc });
 
         // forward peerConnection events
         this.#pc.addEventListener('connectionstatechange', () => {
-            this.dispatchEvent(new Event('statechange'));
-        });
-
-        // forward events to properties
-        this.addEventListener('statechange', (e) => {
-            if (this.onstatechange) this.onstatechange(e);
+            const e = new Event('statechange');
+            this.dispatchEvent(e);
+            this.onstatechange?.(e);
         });
     }
 
@@ -33,15 +29,12 @@ export default class RTCDtlsTransport extends EventTarget implements globalThis.
     get state(): RTCDtlsTransportState {
         // reduce state from new, connecting, connected, disconnected, failed, closed, unknown
         // to RTCDtlsTRansport states new, connecting, connected, closed, failed
-        let state = this.#pc ? this.#pc.connectionState : 'new';
-        if (state === 'disconnected') {
-            state = 'closed';
-        }
-        return state;
+        if (this.#pc.connectionState === 'disconnected') return 'closed'
+        return this.#pc.connectionState
     }
 
     getRemoteCertificates(): ArrayBuffer[] {
-        // TODO: implement
+        // TODO: implement, not supported by all browsers anyways
         return [new ArrayBuffer(0)];
     }
 }
diff --git a/src/polyfill/RTCError.ts b/src/polyfill/RTCError.ts
index 1271bae8..0253fcd8 100644
--- a/src/polyfill/RTCError.ts
+++ b/src/polyfill/RTCError.ts
@@ -1,32 +1,33 @@
+const RTCErrorDetailType = [
+    'data-channel-failure',
+    'dtls-failure',
+    'fingerprint-failure',
+    'sctp-failure',
+    'sdp-syntax-error',
+    'hardware-encoder-not-available',
+    'hardware-encoder-error'
+]
+
 export default class RTCError extends DOMException implements globalThis.RTCError {
     #errorDetail: RTCErrorDetailType;
     #receivedAlert: number | null;
     #sctpCauseCode: number | null;
     #sdpLineNumber: number | null;
     #sentAlert: number | null;
+    #httpRequestStatusCode: number | null;
 
     constructor(init: globalThis.RTCErrorInit, message?: string) {
-        super(message, 'OperationError');
-
-        if (!init || !init.errorDetail) throw new TypeError('Cannot construct RTCError, errorDetail is required');
-        if (
-            [
-                'data-channel-failure',
-                'dtls-failure',
-                'fingerprint-failure',
-                'hardware-encoder-error',
-                'hardware-encoder-not-available',
-                'sctp-failure',
-                'sdp-syntax-error',
-            ].indexOf(init.errorDetail) === -1
-        )
-            throw new TypeError('Cannot construct RTCError, errorDetail is invalid');
+        if (arguments.length === 0) throw new TypeError("Failed to construct 'RTCError': 1 argument required, but only 0 present.")
+        if (!init.errorDetail) throw new TypeError("Failed to construct 'RTCError': Failed to read the 'errorDetail' property from 'RTCErrorInit': Required member is undefined.")
+        if (!RTCErrorDetailType.includes(init.errorDetail)) throw new TypeError(`Failed to construct 'RTCError': Failed to read the 'errorDetail' property from 'RTCErrorInit': The provided value '${init.errorDetail}' is not a valid enum value of type RTCErrorDetailType.`)
+        super(message, 'OperationError')
 
         this.#errorDetail = init.errorDetail;
         this.#receivedAlert = init.receivedAlert ?? null;
         this.#sctpCauseCode = init.sctpCauseCode ?? null;
         this.#sdpLineNumber = init.sdpLineNumber ?? null;
         this.#sentAlert = init.sentAlert ?? null;
+        this.#httpRequestStatusCode = init.httpRequestStatusCode ?? null
     }
 
     get errorDetail(): globalThis.RTCErrorDetailType {
@@ -57,6 +58,10 @@ export default class RTCError extends DOMException implements globalThis.RTCErro
         return this.#sdpLineNumber;
     }
 
+    get httpRequestStatusCode (): number {
+        return this.#httpRequestStatusCode ?? null
+    }
+
     set sdpLineNumber(_value) {
         throw new TypeError('Cannot set sdpLineNumber, it is read-only');
     }
diff --git a/src/polyfill/RTCIceCandidate.ts b/src/polyfill/RTCIceCandidate.ts
index 3f94cad2..f9133c98 100644
--- a/src/polyfill/RTCIceCandidate.ts
+++ b/src/polyfill/RTCIceCandidate.ts
@@ -58,7 +58,7 @@ export default class RTCIceCandidate implements globalThis.RTCIceCandidate {
     }
 
     get address(): string | null {
-        return this.#address || null;
+        return this.#address ?? null;
     }
 
     get candidate(): string {
@@ -70,19 +70,19 @@ export default class RTCIceCandidate implements globalThis.RTCIceCandidate {
     }
 
     get foundation(): string | null {
-        return this.#foundation || null;
+        return this.#foundation ?? null;
     }
 
     get port(): number | null {
-        return this.#port || null;
+        return this.#port ?? null;
     }
 
     get priority(): number | null {
-        return this.#priority || null;
+        return this.#priority ?? null;
     }
 
     get protocol(): globalThis.RTCIceProtocol | null {
-        return this.#protocol || null;
+        return this.#protocol ?? null;
     }
 
     get relatedAddress(): string | null {
@@ -90,7 +90,7 @@ export default class RTCIceCandidate implements globalThis.RTCIceCandidate {
     }
 
     get relatedPort(): number | null {
-        return this.#relatedPort || null;
+        return this.#relatedPort ?? null;
     }
 
     get sdpMLineIndex(): number | null {
@@ -106,7 +106,7 @@ export default class RTCIceCandidate implements globalThis.RTCIceCandidate {
     }
 
     get type(): globalThis.RTCIceCandidateType | null {
-        return this.#type || null;
+        return this.#type ?? null;
     }
 
     get usernameFragment(): string | null {
diff --git a/src/polyfill/RTCIceTransport.ts b/src/polyfill/RTCIceTransport.ts
index 7827d81f..da630f7a 100644
--- a/src/polyfill/RTCIceTransport.ts
+++ b/src/polyfill/RTCIceTransport.ts
@@ -1,73 +1,66 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
 import RTCIceCandidate from './RTCIceCandidate';
 import RTCPeerConnection from './RTCPeerConnection';
 
 export default class RTCIceTransport extends EventTarget implements globalThis.RTCIceTransport {
     #pc: RTCPeerConnection = null;
-    #extraFunctions = null;
 
-    ongatheringstatechange: ((this: RTCIceTransport, ev: Event) => any) | null = null;
-    onselectedcandidatepairchange: ((this: RTCIceTransport, ev: Event) => any) | null = null;
-    onstatechange: ((this: RTCIceTransport, ev: Event) => any) | null = null;
+    ongatheringstatechange: globalThis.RTCIceTransport['ongatheringstatechange'];
+    onselectedcandidatepairchange: globalThis.RTCIceTransport['onselectedcandidatepairchange'];
+    onstatechange: globalThis.RTCIceTransport['onstatechange'];
 
-    constructor(init: { pc: RTCPeerConnection, extraFunctions }) {
+    constructor({ pc }: { pc: RTCPeerConnection }) {
         super();
-        this.#pc = init.pc;
-        this.#extraFunctions = init.extraFunctions;
+        this.#pc = pc;
 
         // forward peerConnection events
-        this.#pc.addEventListener('icegatheringstatechange', () => {
-            this.dispatchEvent(new Event('gatheringstatechange'));
+        pc.addEventListener('icegatheringstatechange', () => {
+            const e = new Event('gatheringstatechange')
+            this.dispatchEvent(e)
+            this.ongatheringstatechange?.(e)
         });
-        this.#pc.addEventListener('iceconnectionstatechange', () => {
-            this.dispatchEvent(new Event('statechange'));
-        });
-
-        // forward events to properties
-        this.addEventListener('gatheringstatechange', (e) => {
-            if (this.ongatheringstatechange) this.ongatheringstatechange(e);
-        });
-        this.addEventListener('statechange', (e) => {
-            if (this.onstatechange) this.onstatechange(e);
+        pc.addEventListener('iceconnectionstatechange', () => {
+            const e = new Event('statechange')
+            this.dispatchEvent(e)
+            this.onstatechange?.(e)
         });
     }
 
     get component(): globalThis.RTCIceComponent {
         const cp = this.getSelectedCandidatePair();
-        if (!cp) return null;
+        if (!cp?.local) return null;
         return cp.local.component;
     }
 
     get gatheringState(): globalThis.RTCIceGatheringState {
-        return this.#pc ? this.#pc.iceGatheringState : 'new';
+        return this.#pc.iceGatheringState;
     }
 
-    get role(): string {
+    get role(): globalThis.RTCIceRole {
         return this.#pc.localDescription.type == 'offer' ? 'controlling' : 'controlled';
     }
 
     get state(): globalThis.RTCIceTransportState {
-        return this.#pc ? this.#pc.iceConnectionState : 'new';
+        return this.#pc.iceConnectionState;
     }
 
     getLocalCandidates(): RTCIceCandidate[] {
-        return this.#pc ? this.#extraFunctions.localCandidates() : [];
+        return this.#pc.localCandidates;
     }
 
-    getLocalParameters(): any {
-        /** */
+    getLocalParameters(): RTCIceParameters | null {
+        return new RTCIceParameters(new RTCIceCandidate({ candidate: this.#pc.getSelectedCandidatePair().local.candidate, sdpMLineIndex: 0 }))
     }
 
     getRemoteCandidates(): RTCIceCandidate[] {
-        return this.#pc ? this.#extraFunctions.remoteCandidates() : [];
+        return this.#pc.remoteCandidates;
     }
 
-    getRemoteParameters(): any {
-        /** */
+    getRemoteParameters(): RTCIceParameters | null {
+        return new RTCIceParameters(new RTCIceCandidate({ candidate: this.#pc.getSelectedCandidatePair().remote.candidate, sdpMLineIndex: 0 }))
     }
 
     getSelectedCandidatePair(): globalThis.RTCIceCandidatePair | null {
-        const cp = this.#extraFunctions.selectedCandidatePair();
+        const cp = this.#pc.getSelectedCandidatePair();
         if (!cp) return null;
         return {
             local: new RTCIceCandidate({
@@ -81,3 +74,13 @@ export default class RTCIceTransport extends EventTarget implements globalThis.R
         };
     }
 }
+
+
+export class RTCIceParameters implements globalThis.RTCIceParameters {
+    usernameFragment = ''
+    password = ''
+    constructor ({ usernameFragment, password = '' }) {
+        this.usernameFragment = usernameFragment
+        this.password = password
+    }
+}
diff --git a/src/polyfill/RTCPeerConnection.ts b/src/polyfill/RTCPeerConnection.ts
index 61920f32..463bd69c 100644
--- a/src/polyfill/RTCPeerConnection.ts
+++ b/src/polyfill/RTCPeerConnection.ts
@@ -1,6 +1,4 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import { SelectedCandidateInfo } from '../lib/types';
-import { PeerConnection } from '../lib/index';
+import { DataChannel, DataChannelInitConfig, PeerConnection } from '../lib/index';
 import RTCSessionDescription from './RTCSessionDescription';
 import RTCDataChannel from './RTCDataChannel';
 import RTCIceCandidate from './RTCIceCandidate';
@@ -20,110 +18,83 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
     }
 
     #peerConnection: PeerConnection;
-    #localOffer: any;
-    #localAnswer: any;
-    #dataChannels: Set<RTCDataChannel>;
+    #localOffer: ReturnType<typeof createDeferredPromise>;
+    #localAnswer: ReturnType<typeof createDeferredPromise>;
+    #dataChannels = new Set<RTCDataChannel>();
     #dataChannelsClosed = 0;
     #config: RTCConfiguration;
-    #canTrickleIceCandidates: boolean | null;
+    #canTrickleIceCandidates: boolean | null = null;
     #sctp: RTCSctpTransport;
+    #announceNegotiation: boolean | null = null;
 
     #localCandidates: RTCIceCandidate[] = [];
     #remoteCandidates: RTCIceCandidate[] = [];
 
     // events
-    onconnectionstatechange: ((this: RTCPeerConnection, ev: Event) => any) | null;
-    ondatachannel: ((this: RTCPeerConnection, ev: RTCDataChannelEvent) => any) | null;
-    onicecandidate: ((this: RTCPeerConnection, ev: RTCPeerConnectionIceEvent) => any) | null;
-    onicecandidateerror: ((this: RTCPeerConnection, ev: Event) => any) | null;
-    oniceconnectionstatechange: ((this: RTCPeerConnection, ev: Event) => any) | null;
-    onicegatheringstatechange: ((this: RTCPeerConnection, ev: Event) => any) | null;
-    onnegotiationneeded: ((this: RTCPeerConnection, ev: Event) => any) | null;
-    onsignalingstatechange: ((this: RTCPeerConnection, ev: Event) => any) | null;
-    ontrack: ((this: RTCPeerConnection, ev: globalThis.RTCTrackEvent) => any) | null;
-
-    private _checkConfiguration(config: RTCConfiguration): void {
-        if (config && config.iceServers === undefined) config.iceServers = [];
-        if (config && config.iceTransportPolicy === undefined) config.iceTransportPolicy = 'all';
-
-        if (config?.iceServers === null) throw new TypeError('IceServers cannot be null');
-
-        // Check for all the properties of iceServers
-        if (Array.isArray(config?.iceServers)) {
-            for (let i = 0; i < config.iceServers.length; i++) {
-                if (config.iceServers[i] === null) throw new TypeError('IceServers cannot be null');
-                if (config.iceServers[i] === undefined) throw new TypeError('IceServers cannot be undefined');
-                if (Object.keys(config.iceServers[i]).length === 0) throw new TypeError('IceServers cannot be empty');
-
-                // If iceServers is string convert to array
-                if (typeof config.iceServers[i].urls === 'string')
-                    config.iceServers[i].urls = [config.iceServers[i].urls as string];
-
-                // urls can not be empty
-                if ((config.iceServers[i].urls as string[])?.some((url) => url == ''))
-                    throw new exceptions.SyntaxError('IceServers urls cannot be empty');
-
-                // urls should be valid URLs and match the protocols "stun:|turn:|turns:"
-                if (
-                    (config.iceServers[i].urls as string[])?.some(
-                        (url) => {
-                            try {
-                                const parsedURL = new URL(url)
-
-                                return !/^(stun:|turn:|turns:)$/.test(parsedURL.protocol)
-                            } catch (error) {
-                                return true
-                            }
-                        },
-                    )
-                )
-                    throw new exceptions.SyntaxError('IceServers urls wrong format');
-
-                // If this is a turn server check for username and credential
-                if ((config.iceServers[i].urls as string[])?.some((url) => url.startsWith('turn'))) {
-                    if (!config.iceServers[i].username)
-                        throw new exceptions.InvalidAccessError('IceServers username cannot be null');
-                    if (!config.iceServers[i].credential)
-                        throw new exceptions.InvalidAccessError('IceServers username cannot be undefined');
-                }
+    onconnectionstatechange: globalThis.RTCPeerConnection['onconnectionstatechange'];
+    ondatachannel: globalThis.RTCPeerConnection['ondatachannel'];
+    onicecandidate: globalThis.RTCPeerConnection['onicecandidate'];
+    // TODO: not implemented
+    onicecandidateerror: globalThis.RTCPeerConnection['onicecandidateerror'];
+    oniceconnectionstatechange: globalThis.RTCPeerConnection['oniceconnectionstatechange'];
+    onicegatheringstatechange: globalThis.RTCPeerConnection['onicegatheringstatechange'];
+    onnegotiationneeded: globalThis.RTCPeerConnection['onnegotiationneeded'];
+    onsignalingstatechange: globalThis.RTCPeerConnection['onsignalingstatechange'];
+    ontrack: globalThis.RTCPeerConnection['ontrack'] | null;
 
-                // length of urls can not be 0
-                if (config.iceServers[i].urls?.length === 0)
-                    throw new exceptions.SyntaxError('IceServers urls cannot be empty');
+    setConfiguration(config: RTCConfiguration): void {
+        // TODO: this doesn't actually update the configuration :/
+            // most of these are unused x)
+            config ??= {}
+            if (config.bundlePolicy === undefined) config.bundlePolicy = 'balanced'
+            // @ts-expect-error non-standard
+            config.encodedInsertableStreams ??= false
+            config.iceCandidatePoolSize ??= 0
+            config.iceServers ??= []
+            for (let { urls } of config.iceServers) {
+                if (!Array.isArray(urls)) urls = [urls]
+                    for (const url of urls) {
+                        try {
+                            new URL(url)
+                        } catch (error) {
+                            throw new DOMException(`Failed to execute 'setConfiguration' on 'RTCPeerConnection': '${url}' is not a valid URL.`, 'SyntaxError')
+                        }
+                    }
+                }
+                config.iceTransportPolicy ??= 'all'
+                // @ts-expect-error non-standard
+                config.rtcAudioJitterBufferFastAccelerate ??= false
+                // @ts-expect-error non-standard
+                config.rtcAudioJitterBufferMaxPackets ??= 200
+                // @ts-expect-error non-standard
+                config.rtcAudioJitterBufferMinDelayMs ??= 0
+                config.rtcpMuxPolicy ??= 'require'
+
+                if (config.iceCandidatePoolSize < 0 || config.iceCandidatePoolSize > 255) throw new TypeError("Failed to execute 'setConfiguration' on 'RTCPeerConnection': Failed to read the 'iceCandidatePoolSize' property from 'RTCConfiguration': Value is outside the 'octet' value range.")
+                if (config.bundlePolicy !== 'balanced' && config.bundlePolicy !== 'max-compat' && config.bundlePolicy !== 'max-bundle') throw new TypeError("Failed to execute 'setConfiguration' on 'RTCPeerConnection': Failed to read the 'bundlePolicy' property from 'RTCConfiguration': The provided value '" + config.bundlePolicy + "' is not a valid enum value of type RTCBundlePolicy.")
+                if (this.#config) {
+                if (config.bundlePolicy !== this.#config.bundlePolicy) {
+                    throw new DOMException("Failed to execute 'setConfiguration' on 'RTCPeerConnection': Attempted to modify the PeerConnection's configuration in an unsupported way.", 'InvalidModificationError')
+                }
             }
-        }
-
-        if (
-            config &&
-            config.iceTransportPolicy &&
-            config.iceTransportPolicy !== 'all' &&
-            config.iceTransportPolicy !== 'relay'
-        )
-            throw new TypeError('IceTransportPolicy must be either "all" or "relay"');
-    }
 
-    setConfiguration(config: RTCConfiguration): void {
-        this._checkConfiguration(config);
-        this.#config = config;
+            this.#config = config
     }
 
 
 
-    constructor(config: RTCConfiguration = { iceServers: [], iceTransportPolicy: 'all' }) {
+    constructor(config: RTCConfiguration = {}) {
         super();
 
-        this._checkConfiguration(config);
-        this.#config = config;
+        this.setConfiguration(config);
         this.#localOffer = createDeferredPromise();
         this.#localAnswer = createDeferredPromise();
-        this.#dataChannels = new Set();
-        this.#canTrickleIceCandidates = null;
 
         try {
-            const peerIdentity = (config as any)?.peerIdentity ?? `peer-${getRandomString(7)}`;
+            const peerIdentity = config?.peerIdentity ?? `peer-${getRandomString(7)}`;
             this.#peerConnection = new PeerConnection(peerIdentity,
                 {
-                    ...config,
+                    ...this.#config,
                     iceServers:
                         config?.iceServers
                             ?.map((server) => {
@@ -163,18 +134,16 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
         });
 
         this.#peerConnection.onDataChannel((channel) => {
-            const dc = new RTCDataChannel(channel);
-            this.#dataChannels.add(dc);
-            this.dispatchEvent(new RTCDataChannelEvent('datachannel', { channel: dc }));
+            this.dispatchEvent(new RTCDataChannelEvent('datachannel', { channel: this.#handleDataChannel(channel) }))
         });
 
         this.#peerConnection.onLocalDescription((sdp, type) => {
             if (type === 'offer') {
-                this.#localOffer.resolve({ sdp, type });
+                this.#localOffer.resolve(new RTCSessionDescription({ sdp, type }));
             }
 
             if (type === 'answer') {
-                this.#localAnswer.resolve({ sdp, type });
+                this.#localAnswer.resolve(new RTCSessionDescription({ sdp, type }));
             }
         });
 
@@ -190,44 +159,42 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
 
         // forward events to properties
         this.addEventListener('connectionstatechange', (e) => {
-            if (this.onconnectionstatechange) this.onconnectionstatechange(e);
+            this.onconnectionstatechange?.(e);
         });
         this.addEventListener('signalingstatechange', (e) => {
-            if (this.onsignalingstatechange) this.onsignalingstatechange(e);
+            this.onsignalingstatechange?.(e);
         });
         this.addEventListener('iceconnectionstatechange', (e) => {
-            if (this.oniceconnectionstatechange) this.oniceconnectionstatechange(e);
+            this.oniceconnectionstatechange?.(e);
         });
         this.addEventListener('icegatheringstatechange', (e) => {
-            if (this.onicegatheringstatechange) this.onicegatheringstatechange(e);
+            this.onicegatheringstatechange?.(e);
         });
         this.addEventListener('datachannel', (e) => {
-            if (this.ondatachannel) this.ondatachannel(e as RTCDataChannelEvent);
+            this.ondatachannel?.(e as RTCDataChannelEvent);
         });
         this.addEventListener('icecandidate', (e) => {
-            if (this.onicecandidate) this.onicecandidate(e as RTCPeerConnectionIceEvent);
+            this.onicecandidate?.(e as RTCPeerConnectionIceEvent);
         });
 
-        this.#sctp = new RTCSctpTransport({
-            pc: this,
-            extraFunctions: {
-                maxDataChannelId: (): number => {
-                    return this.#peerConnection.maxDataChannelId();
-                },
-                maxMessageSize: (): number => {
-                    return this.#peerConnection.maxMessageSize();
-                },
-                localCandidates: (): RTCIceCandidate[] => {
-                    return this.#localCandidates;
-                },
-                remoteCandidates: (): RTCIceCandidate[] => {
-                    return this.#remoteCandidates;
-                },
-                selectedCandidatePair: (): { local: SelectedCandidateInfo; remote: SelectedCandidateInfo } | null => {
-                    return this.#peerConnection.getSelectedCandidatePair();
-                },
-            },
-        });
+        this.addEventListener('track', e => {
+            this.ontrack?.(e as RTCTrackEvent)
+        })
+
+        this.addEventListener('negotiationneeded', e => {
+            this.#announceNegotiation = true
+            this.onnegotiationneeded?.(e)
+        })
+
+        this.#sctp = new RTCSctpTransport({ pc: this });
+    }
+
+    get localCandidates (): RTCIceCandidate[] {
+        return this.#localCandidates
+    }
+    
+    get remoteCandidates (): RTCIceCandidate[] {
+        return this.#remoteCandidates
     }
 
     get canTrickleIceCandidates(): boolean | null {
@@ -250,28 +217,32 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
         return this.#peerConnection.gatheringState();
     }
 
-    get currentLocalDescription(): RTCSessionDescription {
-        return new RTCSessionDescription(this.#peerConnection.localDescription() as any);
+    #nullableDescription (desc): RTCSessionDescription | null {
+        if (!desc) return null
+        return new RTCSessionDescription(desc)
     }
-
-    get currentRemoteDescription(): RTCSessionDescription {
-        return new RTCSessionDescription(this.#peerConnection.remoteDescription() as any);
+    get currentLocalDescription (): RTCSessionDescription {
+        return this.#nullableDescription(this.#peerConnection.localDescription())
     }
-
-    get localDescription(): RTCSessionDescription {
-        return new RTCSessionDescription(this.#peerConnection.localDescription() as any);
+    
+    get currentRemoteDescription (): RTCSessionDescription {
+        return this.#nullableDescription(this.#peerConnection.remoteDescription())
     }
-
-    get pendingLocalDescription(): RTCSessionDescription {
-        return new RTCSessionDescription(this.#peerConnection.localDescription() as any);
+    
+    get localDescription (): RTCSessionDescription {
+        return this.#nullableDescription(this.#peerConnection.localDescription())
     }
-
-    get pendingRemoteDescription(): RTCSessionDescription {
-        return new RTCSessionDescription(this.#peerConnection.remoteDescription() as any);
+    
+    get pendingLocalDescription (): RTCSessionDescription {
+        return this.#nullableDescription(this.#peerConnection.localDescription())
     }
-
-    get remoteDescription(): RTCSessionDescription {
-        return new RTCSessionDescription(this.#peerConnection.remoteDescription() as any);
+    
+    get pendingRemoteDescription (): RTCSessionDescription {
+        return this.#nullableDescription(this.#peerConnection.remoteDescription())
+    }
+    
+    get remoteDescription (): RTCSessionDescription {
+        return this.#nullableDescription(this.#peerConnection.remoteDescription())
     }
 
     get sctp(): RTCSctpTransport {
@@ -283,16 +254,17 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
     }
 
     async addIceCandidate(candidate?: globalThis.RTCIceCandidateInit | null): Promise<void> {
+        // TODO: only resolve this once the candidate is added and not right away
         if (!candidate || !candidate.candidate) {
             return;
         }
 
         if (candidate.sdpMid === null && candidate.sdpMLineIndex === null) {
-            throw new TypeError('sdpMid must be set');
+            throw new DOMException('Candidate invalid');
         }
 
         if (candidate.sdpMid === undefined && candidate.sdpMLineIndex == undefined) {
-            throw new TypeError('sdpMid must be set');
+            throw new DOMException('Candidate invalid');
         }
 
         // Reject if sdpMid format is not valid
@@ -308,9 +280,9 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
         }
 
         try {
-            this.#peerConnection.addRemoteCandidate(candidate.candidate, candidate.sdpMid || '0');
+            this.#peerConnection.addRemoteCandidate(candidate.candidate, candidate.sdpMid ?? '0');
             this.#remoteCandidates.push(
-                new RTCIceCandidate({ candidate: candidate.candidate, sdpMid: candidate.sdpMid || '0' }),
+                new RTCIceCandidate({ candidate: candidate.candidate, sdpMid: candidate.sdpMid ?? '0' }),
             );
         } catch (error) {
             if (!error || !error.message) throw new exceptions.NotFoundError('Unknown error');
@@ -320,18 +292,31 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
                 throw new exceptions.InvalidStateError(error.message);
             if (error.message.includes('Invalid candidate format')) throw new exceptions.OperationError(error.message);
 
-            throw new exceptions.NotFoundError(error.message);
+            throw new DOMException(error.message, 'UnknownError');
         }
     }
-
-    // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    addTrack(_track, ..._streams): globalThis.RTCRtpSender {
-        throw new DOMException('Not implemented');
+    
+    addTrack (): globalThis.RTCRtpSender {
+        return {} as globalThis.RTCRtpSender
     }
+    
 
-    // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    addTransceiver(_trackOrKind, _init): globalThis.RTCRtpTransceiver {
-        throw new DOMException('Not implemented');
+    addTransceiver (): globalThis.RTCRtpTransceiver {
+        return {} as globalThis.RTCRtpTransceiver
+    }
+    
+    getReceivers (): globalThis.RTCRtpReceiver[] {
+        // receivers are created on ontrack
+        return []
+    }
+    
+    getSenders (): globalThis.RTCRtpSender[] {
+        // senders are created on addTrack or addTransceiver
+        return []
+    }
+    
+    getTracks (): globalThis.MediaStreamTrack[] {
+        return []
     }
 
     close(): void {
@@ -344,26 +329,48 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
         this.#peerConnection.close();
     }
 
-    createAnswer(): Promise<globalThis.RTCSessionDescriptionInit | any> {
-        return this.#localAnswer;
+    get maxMessageSize (): number {
+        return this.#peerConnection.maxMessageSize()
+    }
+    
+    get maxChannels (): number {
+        return this.#peerConnection.maxDataChannelId()
     }
 
+    createAnswer(): Promise<globalThis.RTCSessionDescriptionInit> & Promise<void> {
+        // @ts-expect-error dont support deprecated overload
+        return this.#localAnswer;
+    }
 
-    createDataChannel(label, opts = {}): RTCDataChannel {
-        const channel = this.#peerConnection.createDataChannel(label, opts);
-        const dataChannel = new RTCDataChannel(channel, opts);
-
+    #handleDataChannel (channel: DataChannel, opts?: DataChannelInitConfig): RTCDataChannel {
+        const dataChannel = new RTCDataChannel(channel, opts, this)
+    
         // ensure we can close all channels when shutting down
-        this.#dataChannels.add(dataChannel);
+        this.#dataChannels.add(dataChannel)
         dataChannel.addEventListener('close', () => {
-            this.#dataChannels.delete(dataChannel);
-            this.#dataChannelsClosed++;
-        });
-
-        return dataChannel;
+            this.#dataChannels.delete(dataChannel)
+        })
+    
+        return dataChannel
+    }
+
+
+    createDataChannel (label: string, opts: globalThis.RTCDataChannelInit = {}): RTCDataChannel {
+        const conf: DataChannelInitConfig = opts
+        if (opts.ordered === false) conf.unordered = true
+        const channel = this.#peerConnection.createDataChannel('' + label, conf)
+        const dataChannel = this.#handleDataChannel(channel, opts)
+    
+        if (this.#announceNegotiation == null) {
+            this.#announceNegotiation = false
+            this.dispatchEvent(new Event('negotiationneeded'))
+        }
+    
+        return dataChannel
     }
 
-    createOffer(): Promise<globalThis.RTCSessionDescriptionInit | any> {
+    createOffer(): Promise<globalThis.RTCSessionDescriptionInit> & Promise<void> {
+        // @ts-expect-error dont support deprecated overload
         return this.#localOffer;
     }
 
@@ -371,95 +378,93 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
         return this.#config;
     }
 
-    getReceivers(): globalThis.RTCRtpReceiver[] {
-        throw new DOMException('Not implemented');
+    getSelectedCandidatePair () {
+        return this.#peerConnection.getSelectedCandidatePair()
     }
 
-    getSenders(): globalThis.RTCRtpSender[] {
-        throw new DOMException('Not implemented');
-    }
+    
+    getStats(): Promise<globalThis.RTCStatsReport> & Promise<void> {
+        const report = new Map();
+        const cp = this.getSelectedCandidatePair();
+        const bytesSent = this.#peerConnection.bytesSent();
+        const bytesReceived = this.#peerConnection.bytesReceived();
+        const rtt = this.#peerConnection.rtt();
 
-    getStats(): Promise<globalThis.RTCStatsReport> {
-        return new Promise((resolve) => {
-            const report = new Map();
-            const cp = this.#peerConnection?.getSelectedCandidatePair();
-            const bytesSent = this.#peerConnection?.bytesSent();
-            const bytesReceived = this.#peerConnection?.bytesReceived();
-            const rtt = this.#peerConnection?.rtt();
+        if(!cp) {
+            // @ts-expect-error dont support deprecated overload
+            return Promise.resolve(report as globalThis.RTCStatsReport);
+        }
 
-            if(!cp) {
-                return resolve(report);
-            }
+        const localIdRs = getRandomString(8);
+        const localId = 'RTCIceCandidate_' + localIdRs;
+        report.set(localId, {
+            id: localId,
+            type: 'local-candidate',
+            timestamp: Date.now(),
+            candidateType: cp.local.type,
+            ip: cp.local.address,
+            port: cp.local.port,
+        });
+
+        const remoteIdRs = getRandomString(8);
+        const remoteId = 'RTCIceCandidate_' + remoteIdRs;
+        report.set(remoteId, {
+            id: remoteId,
+            type: 'remote-candidate',
+            timestamp: Date.now(),
+            candidateType: cp.remote.type,
+            ip: cp.remote.address,
+            port: cp.remote.port,
+        });
+
+        const candidateId = 'RTCIceCandidatePair_' + localIdRs + '_' + remoteIdRs;
+        report.set(candidateId, {
+            id: candidateId,
+            type: 'candidate-pair',
+            timestamp: Date.now(),
+            localCandidateId: localId,
+            remoteCandidateId: remoteId,
+            state: 'succeeded',
+            nominated: true,
+            writable: true,
+            bytesSent: bytesSent,
+            bytesReceived: bytesReceived,
+            totalRoundTripTime: rtt,
+            currentRoundTripTime: rtt,
+        });
 
-            const localIdRs = getRandomString(8);
-            const localId = 'RTCIceCandidate_' + localIdRs;
-            report.set(localId, {
-                id: localId,
-                type: 'local-candidate',
-                timestamp: Date.now(),
-                candidateType: cp.local.type,
-                ip: cp.local.address,
-                port: cp.local.port,
-            });
-
-            const remoteIdRs = getRandomString(8);
-            const remoteId = 'RTCIceCandidate_' + remoteIdRs;
-            report.set(remoteId, {
-                id: remoteId,
-                type: 'remote-candidate',
-                timestamp: Date.now(),
-                candidateType: cp.remote.type,
-                ip: cp.remote.address,
-                port: cp.remote.port,
-            });
-
-            const candidateId = 'RTCIceCandidatePair_' + localIdRs + '_' + remoteIdRs;
-            report.set(candidateId, {
-                id: candidateId,
-                type: 'candidate-pair',
-                timestamp: Date.now(),
-                localCandidateId: localId,
-                remoteCandidateId: remoteId,
-                state: 'succeeded',
-                nominated: true,
-                writable: true,
-                bytesSent: bytesSent,
-                bytesReceived: bytesReceived,
-                totalRoundTripTime: rtt,
-                currentRoundTripTime: rtt,
-            });
-
-            const transportId = 'RTCTransport_0_1';
-            report.set(transportId, {
-                id: transportId,
-                timestamp: Date.now(),
-                type: 'transport',
-                bytesSent: bytesSent,
-                bytesReceived: bytesReceived,
-                dtlsState: 'connected',
-                selectedCandidatePairId: candidateId,
-                selectedCandidatePairChanges: 1,
-            });
-
-            // peer-connection'
-            report.set('P', {
-                id: 'P',
-                type: 'peer-connection',
-                timestamp: Date.now(),
-                dataChannelsOpened: this.#dataChannels.size,
-                dataChannelsClosed: this.#dataChannelsClosed,
-            });
-
-            return resolve(report);
+        const transportId = 'RTCTransport_0_1';
+        report.set(transportId, {
+            id: transportId,
+            timestamp: Date.now(),
+            type: 'transport',
+            bytesSent: bytesSent,
+            bytesReceived: bytesReceived,
+            dtlsState: 'connected',
+            selectedCandidatePairId: candidateId,
+            selectedCandidatePairChanges: 1,
         });
+
+        // peer-connection'
+        report.set('P', {
+            id: 'P',
+            type: 'peer-connection',
+            timestamp: Date.now(),
+            dataChannelsOpened: this.#dataChannels.size,
+            dataChannelsClosed: this.#dataChannelsClosed,
+        });
+
+        // @ts-expect-error dont support deprecated overload
+        return Promise.resolve(report as globalThis.RTCStatsReport);
     }
 
     getTransceivers(): globalThis.RTCRtpTransceiver[] {
-        return []; // throw new DOMException('Not implemented');
+        return [];
     }
 
     removeTrack(): void {
-        throw new DOMException('Not implemented');
+        console.warn('track detatching not supported')
+        // throw new DOMException('Not implemented');
     }
 
     restartIce(): Promise<void> {
@@ -467,12 +472,17 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
     }
 
     async setLocalDescription(description: globalThis.RTCSessionDescriptionInit): Promise<void> {
-        if (description?.type !== 'offer') {
+        if (description == null || description.type == null) {
+            return this.#peerConnection.setLocalDescription()
+        }
+        // TODO: error and state checking
+
+        if (description.type !== 'offer') {
             // any other type causes libdatachannel to throw
-            return;
+            return this.#peerConnection.setLocalDescription()
         }
 
-        this.#peerConnection.setLocalDescription(description?.type as any);
+        this.#peerConnection.setLocalDescription(description?.type);
     }
 
     async setRemoteDescription(description: globalThis.RTCSessionDescriptionInit): Promise<void> {
@@ -480,21 +490,20 @@ export default class RTCPeerConnection extends EventTarget implements globalThis
             throw new DOMException('Remote SDP must be set');
         }
 
-        this.#peerConnection.setRemoteDescription(description.sdp, description.type as any);
+        this.#peerConnection.setRemoteDescription(description.sdp, description.type);
     }
 }
 
-function createDeferredPromise(): any {
-    let resolve: any, reject: any;
+function createDeferredPromise<T>(): Promise<T> & { resolve: (value: T) => void; reject: (reason?: unknown) => void } {
+    let resolve!: (value: T) => void;
+    let reject!: (reason?: unknown) => void;
 
-    const promise = new Promise(function (_resolve, _reject) {
+    const promise = new Promise<T>((_resolve, _reject) => {
         resolve = _resolve;
         reject = _reject;
     });
 
-    (promise as any).resolve = resolve;
-    (promise as any).reject = reject;
-    return promise;
+    return Object.assign(promise, { resolve, reject });
 }
 
 function getRandomString(length): string {
diff --git a/src/polyfill/RTCSctpTransport.ts b/src/polyfill/RTCSctpTransport.ts
index ade26065..a31d8ff5 100644
--- a/src/polyfill/RTCSctpTransport.ts
+++ b/src/polyfill/RTCSctpTransport.ts
@@ -1,40 +1,33 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
 import RTCDtlsTransport from './RTCDtlsTransport';
 import RTCPeerConnection from './RTCPeerConnection';
 
 export default class RTCSctpTransport extends EventTarget implements globalThis.RTCSctpTransport {
     #pc: RTCPeerConnection = null;
-    #extraFunctions = null;
     #transport: RTCDtlsTransport = null;
 
-    onstatechange: ((this: RTCSctpTransport, ev: Event) => any) | null = null;
+    onstatechange: globalThis.RTCSctpTransport['onstatechange'];
 
-    constructor(initial: { pc: RTCPeerConnection, extraFunctions }) {
+    constructor({ pc }: { pc: RTCPeerConnection }) {
         super();
-        this.#pc = initial.pc;
-        this.#extraFunctions = initial.extraFunctions;
+        this.#pc = pc;
 
-        this.#transport = new RTCDtlsTransport({ pc: initial.pc, extraFunctions: initial.extraFunctions });
+        this.#transport = new RTCDtlsTransport({ pc });
 
-        // forward peerConnection events
-        this.#pc.addEventListener('connectionstatechange', () => {
-            this.dispatchEvent(new Event('statechange'));
-        });
-
-        // forward events to properties
-        this.addEventListener('statechange', (e) => {
-            if (this.onstatechange) this.onstatechange(e);
-        });
+        pc.addEventListener('connectionstatechange', () => {
+            const e = new Event('statechange')
+            this.dispatchEvent(e)
+            this.onstatechange?.(e)
+        })
     }
 
     get maxChannels(): number | null {
         if (this.state !== 'connected') return null;
-        return this.#pc ? this.#extraFunctions.maxDataChannelId() : 0;
+        return this.#pc.maxChannels;
     }
 
     get maxMessageSize(): number {
         if (this.state !== 'connected') return null;
-        return this.#pc ? this.#extraFunctions.maxMessageSize() : 0;
+        return this.#pc.maxMessageSize ?? 65536;
     }
 
     get state(): globalThis.RTCSctpTransportState {
diff --git a/src/polyfill/RTCSessionDescription.ts b/src/polyfill/RTCSessionDescription.ts
index ef0fcb49..e96ef2a9 100644
--- a/src/polyfill/RTCSessionDescription.ts
+++ b/src/polyfill/RTCSessionDescription.ts
@@ -6,19 +6,26 @@
 //     sdp: 'v=0\r\no=- 1234567890 1234567890 IN IP4 192.168.1.1\r\ns=-\r\nt=0 0\r\na=ice-ufrag:abcd\r\na=ice-pwd:efgh\r\n'
 //   };
 
-export default class RTCSessionDescription implements globalThis.RTCSessionDescriptionInit {
+export default class RTCSessionDescription implements globalThis.RTCSessionDescription {
     #type: globalThis.RTCSdpType;
     #sdp: string;
 
-    constructor(init: globalThis.RTCSessionDescriptionInit) {
-        this.#type = init ? init.type : null;
-        this.#sdp = init ? init.sdp : null;
+    constructor(init: globalThis.RTCSessionDescriptionInit | null | undefined) {
+        this.#type = init?.type;
+        this.#sdp = init?.sdp ?? '';
     }
 
     get type(): globalThis.RTCSdpType {
         return this.#type;
     }
 
+    set type (type) {
+        if (type !== 'offer' && type !== 'answer' && type !== 'pranswer' && type !== 'rollback') {
+            throw new TypeError(`Failed to set the 'type' property on 'RTCSessionDescription': The provided value '${type}' is not a valid enum value of type RTCSdpType.`)
+        }
+        this.#type = type
+    }
+
     get sdp(): string {
         return this.#sdp;
     }
diff --git a/src/polyfill/index.ts b/src/polyfill/index.ts
index e8eb53e6..24e65e61 100644
--- a/src/polyfill/index.ts
+++ b/src/polyfill/index.ts
@@ -1,38 +1,12 @@
-import RTCCertificate from './RTCCertificate';
-import RTCDataChannel from './RTCDataChannel';
-import RTCDtlsTransport from './RTCDtlsTransport';
-import RTCIceCandidate from './RTCIceCandidate';
-import RTCIceTransport from './RTCIceTransport';
-import RTCPeerConnection from './RTCPeerConnection';
-import RTCSctpTransport from './RTCSctpTransport';
-import RTCSessionDescription from './RTCSessionDescription';
-import { RTCDataChannelEvent, RTCPeerConnectionIceEvent } from './Events';
-import RTCError from './RTCError';
+export { default as RTCPeerConnection } from './RTCPeerConnection.ts'
+export { default as RTCSessionDescription } from './RTCSessionDescription.ts'
+export { default as RTCIceCandidate } from './RTCIceCandidate.ts'
+export { default as RTCIceTransport } from './RTCIceTransport.ts'
+export { default as RTCDataChannel } from './RTCDataChannel.ts'
+export { default as RTCSctpTransport } from './RTCSctpTransport.ts'
+export { default as RTCDtlsTransport } from './RTCDtlsTransport.ts'
+export { default as RTCCertificate } from './RTCCertificate.ts'
+export * from './Events.ts'
+export * from './RTCError.ts'
 
-export {
-    RTCCertificate,
-    RTCDataChannel,
-    RTCDtlsTransport,
-    RTCIceCandidate,
-    RTCIceTransport,
-    RTCPeerConnection,
-    RTCSctpTransport,
-    RTCSessionDescription,
-    RTCDataChannelEvent,
-    RTCPeerConnectionIceEvent,
-    RTCError,
-};
-
-export default {
-    RTCCertificate,
-    RTCDataChannel,
-    RTCDtlsTransport,
-    RTCIceCandidate,
-    RTCIceTransport,
-    RTCPeerConnection,
-    RTCSctpTransport,
-    RTCSessionDescription,
-    RTCDataChannelEvent,
-    RTCPeerConnectionIceEvent,
-    RTCError,
-};
+export * as default from './index.ts'
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 96d23793..003c20b1 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -7,15 +7,22 @@
     "esModuleInterop": true,
     "skipLibCheck": true,
     "forceConsistentCasingInFileNames": true,
-    "noImplicitAny": false,
-    "noImplicitThis": false,
     "noImplicitReturns": true,
-    "strictNullChecks": false,
     "noUnusedLocals": true,
     "alwaysStrict": true,
+    "allowImportingTsExtensions": true,
+    "noEmit": true,
     "outDir": "./dist",
     "module": "CommonJS"
   },
-  "include": ["src/**/*", "test/**/*"],
-  "exclude": ["node_modules", "dist", "src/cpp", "test/wpt-tests/wpt"]
-}
+  "include": [
+    "src/**/*",
+    "test/**/*"
+  ],
+  "exclude": [
+    "node_modules",
+    "dist",
+    "src/cpp",
+    "test/wpt-tests/wpt"
+  ]
+}
\ No newline at end of file