diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index 0b7038ed2..ad1a43318 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -96,12 +96,6 @@ import com.vitorpamplona.quartz.nip03Timestamp.VerificationStateCache import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent import com.vitorpamplona.quartz.nip09Deletions.DeletionEvent import com.vitorpamplona.quartz.nip09Deletions.DeletionIndex -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallAnswerEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallHangupEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallIceCandidateEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallOfferEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallRejectEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallRenegotiateEvent import com.vitorpamplona.quartz.nip10Notes.BaseNoteEvent import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip17Dm.files.ChatMessageEncryptedFileHeaderEvent diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt index 88a628fe9..b36bf9d3d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/DecryptAndIndexProcessor.kt @@ -28,12 +28,6 @@ import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.IEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallAnswerEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallHangupEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallIceCandidateEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallOfferEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallRejectEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallRenegotiateEvent import com.vitorpamplona.quartz.nip17Dm.base.ChatroomKeyable import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent import com.vitorpamplona.quartz.nip37Drafts.DraftWrapEvent @@ -43,6 +37,12 @@ import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent import com.vitorpamplona.quartz.nip57Zaps.PrivateZapCache import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent +import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallAnswerEvent +import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallHangupEvent +import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallIceCandidateEvent +import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallOfferEvent +import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallRejectEvent +import com.vitorpamplona.quartz.nipACWebRtcCalls.events.CallRenegotiateEvent import com.vitorpamplona.quartz.utils.Log import kotlinx.coroutines.CancellationException diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/NIP-100.md b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/NIP-100.md deleted file mode 100644 index c239fbe2d..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/NIP-100.md +++ /dev/null @@ -1,265 +0,0 @@ -NIP-100 -======= - -WebRTC Calls ------------- - -`draft` `optional` - -This NIP defines a protocol for establishing peer-to-peer voice and video calls between Nostr users using WebRTC, with Nostr relays serving as the signaling transport. - -## Motivation - -Nostr users currently lack a way to make real-time voice or video calls without relying on centralized services. By using Nostr relays for WebRTC signaling and public STUN servers for NAT traversal, calls can be established in a fully decentralized manner — no custom server infrastructure is required. Once a WebRTC peer connection is established, the relay is no longer involved in the media stream. - -## Overview - -The protocol works as follows: - -1. **Caller** creates a signed call offer event containing an SDP offer -2. The event is **gift-wrapped** ([NIP-59](https://github.com/nostr-protocol/nips/blob/master/59.md)) and published to relays -3. **Callee** unwraps the event, verifies the signature, and decides whether to accept -4. If accepted, callee sends back a gift-wrapped call answer event containing an SDP answer -5. Both parties exchange **ICE candidates** as gift-wrapped events for NAT traversal -6. A **direct WebRTC peer connection** is established for audio/video - -All signaling events MUST be gift-wrapped using [NIP-59](https://github.com/nostr-protocol/nips/blob/master/59.md) for metadata privacy. Events are signed by the sender's key and wrapped directly (without the seal layer) — the gift wrap's random ephemeral key already hides the sender from relay operators. - -## Event Kinds - -| Kind | Name | Description | -|-------|---------------------|----------------------------------------------| -| 25050 | Call Offer | SDP offer initiating a call | -| 25051 | Call Answer | SDP answer accepting a call | -| 25052 | ICE Candidate | ICE candidate for NAT traversal | -| 25053 | Call Hangup | Terminates an active or pending call | -| 25054 | Call Reject | Rejects an incoming call | -| 25055 | Call Renegotiate | New SDP offer for mid-call changes | - -## Tags - -All signaling events MUST include: - -| Tag | Description | Required | -|---------------|-------------------------------------------------------|----------| -| `p` | Hex pubkey of the recipient | YES | -| `call-id` | UUID identifying the call session | YES | -| `expiration` | Unix timestamp ([NIP-40](https://github.com/nostr-protocol/nips/blob/master/40.md)), SHOULD be ~5 minutes from `created_at` | YES | -| `alt` | Human-readable description ([NIP-31](https://github.com/nostr-protocol/nips/blob/master/31.md)) | YES | - -Additional tags for **Call Offer** (kind 25050): - -| Tag | Description | Required | -|---------------|-------------------------------------------------------|----------| -| `call-type` | `"voice"` or `"video"` | YES | - -## Event Structures - -### Call Offer (kind 25050) - -The `content` field contains the SDP offer string. - -```json -{ - "kind": 25050, - "pubkey": "", - "created_at": 1234567890, - "content": "v=0\r\no=- 4611731400430051336 2 IN IP4 127.0.0.1\r\n...", - "tags": [ - ["p", ""], - ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["call-type", "video"], - ["expiration", "1234568190"], - ["alt", "WebRTC call offer"] - ], - "id": "", - "sig": "" -} -``` - -### Call Answer (kind 25051) - -The `content` field contains the SDP answer string. - -```json -{ - "kind": 25051, - "pubkey": "", - "created_at": 1234567895, - "content": "v=0\r\no=- 4611731400430051337 2 IN IP4 127.0.0.1\r\n...", - "tags": [ - ["p", ""], - ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["expiration", "1234568195"], - ["alt", "WebRTC call answer"] - ], - "id": "", - "sig": "" -} -``` - -### ICE Candidate (kind 25052) - -The `content` field contains the ICE candidate as a JSON string with the fields `candidate`, `sdpMid`, and `sdpMLineIndex`. - -```json -{ - "kind": 25052, - "pubkey": "", - "created_at": 1234567896, - "content": "{\"candidate\":\"candidate:842163049 1 udp 1677729535 203.0.113.1 44323 typ srflx raddr 0.0.0.0 rport 0 generation 0\",\"sdpMid\":\"0\",\"sdpMLineIndex\":0}", - "tags": [ - ["p", ""], - ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["expiration", "1234568196"], - ["alt", "WebRTC ICE candidate"] - ], - "id": "", - "sig": "" -} -``` - -### Call Hangup (kind 25053) - -The `content` field MAY contain a human-readable reason or be empty. - -```json -{ - "kind": 25053, - "pubkey": "", - "created_at": 1234568000, - "content": "", - "tags": [ - ["p", ""], - ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["expiration", "1234568300"], - ["alt", "WebRTC call hangup"] - ], - "id": "", - "sig": "" -} -``` - -### Call Reject (kind 25054) - -The `content` field MAY contain a reason or be empty. - -```json -{ - "kind": 25054, - "pubkey": "", - "created_at": 1234567893, - "content": "", - "tags": [ - ["p", ""], - ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["expiration", "1234568193"], - ["alt", "WebRTC call rejection"] - ], - "id": "", - "sig": "" -} -``` - -### Call Renegotiate (kind 25055) - -Used for mid-call changes such as toggling video on/off. The `content` field contains a new SDP offer. - -```json -{ - "kind": 25055, - "pubkey": "", - "created_at": 1234568100, - "content": "v=0\r\no=- 4611731400430051338 3 IN IP4 127.0.0.1\r\n...", - "tags": [ - ["p", ""], - ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["expiration", "1234568400"], - ["alt", "WebRTC call renegotiation"] - ], - "id": "", - "sig": "" -} -``` - -## Encryption and Delivery - -All signaling events MUST be delivered using [NIP-59](https://github.com/nostr-protocol/nips/blob/master/59.md) Gift Wraps: - -1. **Sign** the signaling event with the sender's key -2. **Gift-wrap** the signed event directly using `GiftWrapEvent` (kind 1059) with NIP-44 encryption -3. **Publish** the gift wrap to the recipient's relay list - -The seal layer (`SealedRumorEvent`) is NOT used. The gift wrap already provides: - -- **NIP-44 encryption** — content is unreadable to relay operators -- **Random ephemeral pubkey** — the relay cannot identify the sender -- **`p` tag** — reveals only the recipient (necessary for delivery) - -Recipients unwrap the gift, verify the inner event's signature against the sender's pubkey, and then process the signaling message. - -## Protocol Flow - -### Initiating a Call - -``` -Caller Relay Callee - | | | - |-- GiftWrap(CallOffer) ------->| | - | |-- GiftWrap(CallOffer) ------->| - | | | - | | [Callee unwraps, verifies signature] - | | [Checks: is caller followed?] - | | [YES → ring / NO → ignore] - | | | - |<-- GiftWrap(CallAnswer) ------|<-- GiftWrap(CallAnswer) ------| - | | | - |<-> GiftWrap(IceCandidate) <-->|<-> GiftWrap(IceCandidate) <-->| - | | | - |============= WebRTC P2P Connection Established ===============| - | (relay no longer involved) | -``` - -### Ending a Call - -Either party may send a `CallHangup` (kind 25053) at any time. The recipient SHOULD close the WebRTC peer connection and release media resources upon receiving it. - -### Rejecting a Call - -The callee may send a `CallReject` (kind 25054) instead of a `CallAnswer`. The caller SHOULD stop ringing and display a "call rejected" state. - -## Spam Prevention - -Clients SHOULD implement call filtering: - -- **Follow-gated ringing**: Only display incoming call notifications for users in the recipient's follow list. Calls from non-followed users SHOULD be silently ignored. -- **Rate limiting**: Clients SHOULD ignore duplicate call offers from the same pubkey within a short window. -- **Expiration enforcement**: Clients MUST check the `expiration` tag and discard signaling events that have expired. - -## NAT Traversal - -This NIP does not mandate specific STUN or TURN servers. Clients SHOULD: - -- Ship with a default set of public STUN servers (e.g., `stun:stun.l.google.com:19302`) -- Allow users to configure custom TURN servers for restrictive network environments -- Use trickle ICE (sending candidates as they are discovered) rather than waiting for all candidates before sending the offer/answer - -## Implementation Notes - -- The `call-id` tag MUST be a UUID that is unique per call session. All signaling events for the same call share the same `call-id`. -- Events SHOULD have short expiration times (~5 minutes) since signaling data is ephemeral and has no long-term value. -- Clients SHOULD implement a ringing timeout (e.g., 60 seconds). If no answer is received, the call transitions to a "timed out" state. -- Clients SHOULD use a foreground service or equivalent mechanism to keep calls active when the app is backgrounded. -- The WebRTC `PeerConnection` SHOULD use Unified Plan SDP semantics. -- Clients MAY support call renegotiation (kind 25055) for toggling video on/off mid-call without tearing down the connection. - -## References - -- [NIP-01: Basic Protocol](https://github.com/nostr-protocol/nips/blob/master/01.md) — Event structure -- [NIP-31: Alt Tag](https://github.com/nostr-protocol/nips/blob/master/31.md) — Human-readable event descriptions -- [NIP-40: Expiration](https://github.com/nostr-protocol/nips/blob/master/40.md) — Event expiration timestamps -- [NIP-44: Encryption](https://github.com/nostr-protocol/nips/blob/master/44.md) — XChaCha20-Poly1305 encryption -- [NIP-59: Gift Wraps](https://github.com/nostr-protocol/nips/blob/master/59.md) — Encrypted event delivery -- [WebRTC Specification](https://www.w3.org/TR/webrtc/) — Peer-to-peer real-time communication -- [RFC 8445: ICE](https://datatracker.ietf.org/doc/html/rfc8445) — Interactive Connectivity Establishment -- [nostr-protocol/nips#771](https://github.com/nostr-protocol/nips/issues/771) — WebRTC signaling discussion diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/WebRtcCallFactory.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/WebRtcCallFactory.kt deleted file mode 100644 index 858c5b591..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/WebRtcCallFactory.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip100WebRtcCalls - -import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallAnswerEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallHangupEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallIceCandidateEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallOfferEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallRejectEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallRenegotiateEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.CallType -import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent - -class WebRtcCallFactory { - data class Result( - val msg: Event, - val wrap: GiftWrapEvent, - ) - - suspend fun createCallOffer( - sdpOffer: String, - calleePubKey: HexKey, - callId: String, - callType: CallType, - signer: NostrSigner, - ): Result { - val template = CallOfferEvent.build(sdpOffer, calleePubKey, callId, callType) - val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = calleePubKey) - return Result(signed, wrap) - } - - suspend fun createCallAnswer( - sdpAnswer: String, - callerPubKey: HexKey, - callId: String, - signer: NostrSigner, - ): Result { - val template = CallAnswerEvent.build(sdpAnswer, callerPubKey, callId) - val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = callerPubKey) - return Result(signed, wrap) - } - - suspend fun createIceCandidate( - candidateJson: String, - peerPubKey: HexKey, - callId: String, - signer: NostrSigner, - ): Result { - val template = CallIceCandidateEvent.build(candidateJson, peerPubKey, callId) - val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = peerPubKey) - return Result(signed, wrap) - } - - suspend fun createHangup( - peerPubKey: HexKey, - callId: String, - reason: String = "", - signer: NostrSigner, - ): Result { - val template = CallHangupEvent.build(peerPubKey, callId, reason) - val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = peerPubKey) - return Result(signed, wrap) - } - - suspend fun createReject( - callerPubKey: HexKey, - callId: String, - reason: String = "", - signer: NostrSigner, - ): Result { - val template = CallRejectEvent.build(callerPubKey, callId, reason) - val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = callerPubKey) - return Result(signed, wrap) - } - - suspend fun createRenegotiate( - sdpOffer: String, - peerPubKey: HexKey, - callId: String, - signer: NostrSigner, - ): Result { - val template = CallRenegotiateEvent.build(sdpOffer, peerPubKey, callId) - val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = peerPubKey) - return Result(signed, wrap) - } -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallAnswerEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallAnswerEvent.kt deleted file mode 100644 index b09c7da97..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallAnswerEvent.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip100WebRtcCalls.events - -import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.people.pTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.CallIdTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.callId -import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nip40Expiration.expiration -import com.vitorpamplona.quartz.utils.TimeUtils - -@Immutable -class CallAnswerEvent( - id: HexKey, - pubKey: HexKey, - createdAt: Long, - tags: Array>, - content: String, - sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - - fun sdpAnswer() = content - - companion object { - const val KIND = 25051 - const val ALT_DESCRIPTION = "WebRTC call answer" - const val EXPIRATION_SECONDS = 300L - - fun build( - sdpAnswer: String, - callerPubKey: HexKey, - callId: String, - createdAt: Long = TimeUtils.now(), - initializer: TagArrayBuilder.() -> Unit = {}, - ) = eventTemplate(KIND, sdpAnswer, createdAt) { - alt(ALT_DESCRIPTION) - pTag(callerPubKey) - callId(callId) - expiration(createdAt + EXPIRATION_SECONDS) - initializer() - } - } -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallHangupEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallHangupEvent.kt deleted file mode 100644 index 648cb6489..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallHangupEvent.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip100WebRtcCalls.events - -import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.people.pTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.CallIdTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.callId -import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nip40Expiration.expiration -import com.vitorpamplona.quartz.utils.TimeUtils - -@Immutable -class CallHangupEvent( - id: HexKey, - pubKey: HexKey, - createdAt: Long, - tags: Array>, - content: String, - sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - - fun reason() = content.ifEmpty { null } - - companion object { - const val KIND = 25053 - const val ALT_DESCRIPTION = "WebRTC call hangup" - const val EXPIRATION_SECONDS = 300L - - fun build( - peerPubKey: HexKey, - callId: String, - reason: String = "", - createdAt: Long = TimeUtils.now(), - initializer: TagArrayBuilder.() -> Unit = {}, - ) = eventTemplate(KIND, reason, createdAt) { - alt(ALT_DESCRIPTION) - pTag(peerPubKey) - callId(callId) - expiration(createdAt + EXPIRATION_SECONDS) - initializer() - } - } -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallIceCandidateEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallIceCandidateEvent.kt deleted file mode 100644 index 8a3d13087..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallIceCandidateEvent.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip100WebRtcCalls.events - -import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.people.pTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.CallIdTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.callId -import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nip40Expiration.expiration -import com.vitorpamplona.quartz.utils.TimeUtils - -@Immutable -class CallIceCandidateEvent( - id: HexKey, - pubKey: HexKey, - createdAt: Long, - tags: Array>, - content: String, - sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - - fun candidateJson() = content - - companion object { - const val KIND = 25052 - const val ALT_DESCRIPTION = "WebRTC ICE candidate" - const val EXPIRATION_SECONDS = 300L - - fun build( - candidateJson: String, - peerPubKey: HexKey, - callId: String, - createdAt: Long = TimeUtils.now(), - initializer: TagArrayBuilder.() -> Unit = {}, - ) = eventTemplate(KIND, candidateJson, createdAt) { - alt(ALT_DESCRIPTION) - pTag(peerPubKey) - callId(callId) - expiration(createdAt + EXPIRATION_SECONDS) - initializer() - } - } -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallOfferEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallOfferEvent.kt deleted file mode 100644 index e4cd9be14..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallOfferEvent.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip100WebRtcCalls.events - -import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.people.pTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.CallIdTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.CallType -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.CallTypeTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.callId -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.callType -import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nip40Expiration.expiration -import com.vitorpamplona.quartz.utils.TimeUtils - -@Immutable -class CallOfferEvent( - id: HexKey, - pubKey: HexKey, - createdAt: Long, - tags: Array>, - content: String, - sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - - fun callType() = tags.firstNotNullOfOrNull(CallTypeTag::parse) - - fun sdpOffer() = content - - companion object { - const val KIND = 25050 - const val ALT_DESCRIPTION = "WebRTC call offer" - const val EXPIRATION_SECONDS = 300L // 5 minutes - - fun build( - sdpOffer: String, - calleePubKey: HexKey, - callId: String, - type: CallType, - createdAt: Long = TimeUtils.now(), - initializer: TagArrayBuilder.() -> Unit = {}, - ) = eventTemplate(KIND, sdpOffer, createdAt) { - alt(ALT_DESCRIPTION) - pTag(calleePubKey) - callId(callId) - callType(type) - expiration(createdAt + EXPIRATION_SECONDS) - initializer() - } - } -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallRejectEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallRejectEvent.kt deleted file mode 100644 index 84be6ad0f..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallRejectEvent.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip100WebRtcCalls.events - -import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.people.pTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.CallIdTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.callId -import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nip40Expiration.expiration -import com.vitorpamplona.quartz.utils.TimeUtils - -@Immutable -class CallRejectEvent( - id: HexKey, - pubKey: HexKey, - createdAt: Long, - tags: Array>, - content: String, - sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - - fun reason() = content.ifEmpty { null } - - companion object { - const val KIND = 25054 - const val ALT_DESCRIPTION = "WebRTC call rejection" - const val EXPIRATION_SECONDS = 300L - - fun build( - callerPubKey: HexKey, - callId: String, - reason: String = "", - createdAt: Long = TimeUtils.now(), - initializer: TagArrayBuilder.() -> Unit = {}, - ) = eventTemplate(KIND, reason, createdAt) { - alt(ALT_DESCRIPTION) - pTag(callerPubKey) - callId(callId) - expiration(createdAt + EXPIRATION_SECONDS) - initializer() - } - } -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallRenegotiateEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallRenegotiateEvent.kt deleted file mode 100644 index f38898f70..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/events/CallRenegotiateEvent.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip100WebRtcCalls.events - -import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder -import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate -import com.vitorpamplona.quartz.nip01Core.tags.people.pTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.CallIdTag -import com.vitorpamplona.quartz.nip100WebRtcCalls.tags.callId -import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nip40Expiration.expiration -import com.vitorpamplona.quartz.utils.TimeUtils - -@Immutable -class CallRenegotiateEvent( - id: HexKey, - pubKey: HexKey, - createdAt: Long, - tags: Array>, - content: String, - sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - - fun sdpOffer() = content - - companion object { - const val KIND = 25055 - const val ALT_DESCRIPTION = "WebRTC call renegotiation" - const val EXPIRATION_SECONDS = 300L - - fun build( - sdpOffer: String, - peerPubKey: HexKey, - callId: String, - createdAt: Long = TimeUtils.now(), - initializer: TagArrayBuilder.() -> Unit = {}, - ) = eventTemplate(KIND, sdpOffer, createdAt) { - alt(ALT_DESCRIPTION) - pTag(peerPubKey) - callId(callId) - expiration(createdAt + EXPIRATION_SECONDS) - initializer() - } - } -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/tags/CallIdTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/tags/CallIdTag.kt deleted file mode 100644 index d70865550..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/tags/CallIdTag.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip100WebRtcCalls.tags - -import com.vitorpamplona.quartz.nip01Core.core.has -import com.vitorpamplona.quartz.utils.ensure - -class CallIdTag { - companion object { - const val TAG_NAME = "call-id" - - fun parse(tag: Array): String? { - ensure(tag.has(1)) { return null } - ensure(tag[0] == TAG_NAME) { return null } - ensure(tag[1].isNotEmpty()) { return null } - return tag[1] - } - - fun assemble(callId: String) = arrayOf(TAG_NAME, callId) - } -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/tags/CallTypeTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/tags/CallTypeTag.kt deleted file mode 100644 index f0b055af9..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/tags/CallTypeTag.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip100WebRtcCalls.tags - -import com.vitorpamplona.quartz.nip01Core.core.has -import com.vitorpamplona.quartz.utils.ensure - -enum class CallType( - val value: String, -) { - VOICE("voice"), - VIDEO("video"), - ; - - companion object { - fun fromString(value: String): CallType? = - when (value) { - "voice" -> VOICE - "video" -> VIDEO - else -> null - } - } -} - -class CallTypeTag { - companion object { - const val TAG_NAME = "call-type" - - fun parse(tag: Array): CallType? { - ensure(tag.has(1)) { return null } - ensure(tag[0] == TAG_NAME) { return null } - return CallType.fromString(tag[1]) - } - - fun assemble(callType: CallType) = arrayOf(TAG_NAME, callType.value) - } -} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/tags/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/tags/TagArrayBuilderExt.kt deleted file mode 100644 index 17631ee78..000000000 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip100WebRtcCalls/tags/TagArrayBuilderExt.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.quartz.nip100WebRtcCalls.tags - -import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder - -fun TagArrayBuilder.callId(callId: String) = addUnique(CallIdTag.assemble(callId)) - -fun TagArrayBuilder.callType(callType: CallType) = addUnique(CallTypeTag.assemble(callType)) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/EventFactory.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/EventFactory.kt index 48f0d8f04..c4eb7d8d5 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/EventFactory.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/EventFactory.kt @@ -50,12 +50,6 @@ import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent import com.vitorpamplona.quartz.nip03Timestamp.OtsEvent import com.vitorpamplona.quartz.nip04Dm.messages.PrivateDmEvent import com.vitorpamplona.quartz.nip09Deletions.DeletionEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallAnswerEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallHangupEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallIceCandidateEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallOfferEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallRejectEvent -import com.vitorpamplona.quartz.nip100WebRtcCalls.events.CallRenegotiateEvent import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.nip15Marketplace.auction.AuctionEvent import com.vitorpamplona.quartz.nip15Marketplace.bid.BidEvent