mirror of
https://github.com/xtr-dev/rondevu-client.git
synced 2025-12-14 21:03:23 +00:00
Compare commits
5 Commits
add-claude
...
v0.18.1
| Author | SHA1 | Date | |
|---|---|---|---|
| db28a133bf | |||
|
|
4d90cce9d0 | ||
|
|
f5e202384a | ||
|
|
62a6cdcb99 | ||
|
|
febe3b7270 |
16
package-lock.json
generated
16
package-lock.json
generated
@@ -1,16 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "@xtr-dev/rondevu-client",
|
"name": "@xtr-dev/rondevu-client",
|
||||||
"version": "0.18.0",
|
"version": "0.18.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@xtr-dev/rondevu-client",
|
"name": "@xtr-dev/rondevu-client",
|
||||||
"version": "0.18.0",
|
"version": "0.18.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/ed25519": "^3.0.0",
|
"@noble/ed25519": "^3.0.0"
|
||||||
"@xtr-dev/rondevu-client": "^0.9.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.1",
|
||||||
@@ -1310,15 +1309,6 @@
|
|||||||
"url": "https://opencollective.com/eslint"
|
"url": "https://opencollective.com/eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@xtr-dev/rondevu-client": {
|
|
||||||
"version": "0.9.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@xtr-dev/rondevu-client/-/rondevu-client-0.9.2.tgz",
|
|
||||||
"integrity": "sha512-DVow5AOPU40dqQtlfQK7J2GNX8dz2/4UzltMqublaPZubbkRYgocvp0b76NQu5F6v150IstMV2N49uxAYqogVw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@noble/ed25519": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.15.0",
|
"version": "8.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@xtr-dev/rondevu-client",
|
"name": "@xtr-dev/rondevu-client",
|
||||||
"version": "0.18.0",
|
"version": "0.18.1",
|
||||||
"description": "TypeScript client for Rondevu with durable WebRTC connections, automatic reconnection, and message queuing",
|
"description": "TypeScript client for Rondevu with durable WebRTC connections, automatic reconnection, and message queuing",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
@@ -418,11 +418,42 @@ export class Rondevu {
|
|||||||
this.debug('Creating new offer...')
|
this.debug('Creating new offer...')
|
||||||
|
|
||||||
// Create the offer using the factory
|
// Create the offer using the factory
|
||||||
|
// Note: The factory may call setLocalDescription() which triggers ICE gathering
|
||||||
const { pc, dc, offer } = await this.offerFactory(rtcConfig)
|
const { pc, dc, offer } = await this.offerFactory(rtcConfig)
|
||||||
|
|
||||||
// Auto-append username to service
|
// Auto-append username to service
|
||||||
const serviceFqn = `${this.currentService}@${this.username}`
|
const serviceFqn = `${this.currentService}@${this.username}`
|
||||||
|
|
||||||
|
// Queue to buffer ICE candidates generated before we have the offerId
|
||||||
|
// This fixes the race condition where ICE candidates are lost because
|
||||||
|
// they're generated before we can set up the handler with the offerId
|
||||||
|
const earlyIceCandidates: RTCIceCandidateInit[] = []
|
||||||
|
let offerId: string | null = null
|
||||||
|
|
||||||
|
// Set up a queuing ICE candidate handler immediately after getting the pc
|
||||||
|
// This captures any candidates that fire before we have the offerId
|
||||||
|
pc.onicecandidate = async (event) => {
|
||||||
|
if (event.candidate) {
|
||||||
|
// Handle both browser and Node.js (wrtc) environments
|
||||||
|
const candidateData = typeof event.candidate.toJSON === 'function'
|
||||||
|
? event.candidate.toJSON()
|
||||||
|
: event.candidate
|
||||||
|
|
||||||
|
if (offerId) {
|
||||||
|
// We have the offerId, send directly
|
||||||
|
try {
|
||||||
|
await this.api.addOfferIceCandidates(serviceFqn, offerId, [candidateData])
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[Rondevu] Failed to send ICE candidate:', err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Queue for later - we don't have the offerId yet
|
||||||
|
this.debug('Queuing early ICE candidate')
|
||||||
|
earlyIceCandidates.push(candidateData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Publish to server
|
// Publish to server
|
||||||
const result = await this.api.publishService({
|
const result = await this.api.publishService({
|
||||||
serviceFqn,
|
serviceFqn,
|
||||||
@@ -432,7 +463,7 @@ export class Rondevu {
|
|||||||
message: '',
|
message: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const offerId = result.offers[0].offerId
|
offerId = result.offers[0].offerId
|
||||||
|
|
||||||
// Store active offer
|
// Store active offer
|
||||||
this.activeOffers.set(offerId, {
|
this.activeOffers.set(offerId, {
|
||||||
@@ -446,15 +477,22 @@ export class Rondevu {
|
|||||||
|
|
||||||
this.debug(`Offer created: ${offerId}`)
|
this.debug(`Offer created: ${offerId}`)
|
||||||
|
|
||||||
// Set up ICE candidate handler
|
// Send any queued early ICE candidates
|
||||||
this.setupIceCandidateHandler(pc, serviceFqn, offerId)
|
if (earlyIceCandidates.length > 0) {
|
||||||
|
this.debug(`Sending ${earlyIceCandidates.length} early ICE candidates`)
|
||||||
|
try {
|
||||||
|
await this.api.addOfferIceCandidates(serviceFqn, offerId, earlyIceCandidates)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[Rondevu] Failed to send early ICE candidates:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Monitor connection state
|
// Monitor connection state
|
||||||
pc.onconnectionstatechange = () => {
|
pc.onconnectionstatechange = () => {
|
||||||
this.debug(`Offer ${offerId} connection state: ${pc.connectionState}`)
|
this.debug(`Offer ${offerId} connection state: ${pc.connectionState}`)
|
||||||
|
|
||||||
if (pc.connectionState === 'failed' || pc.connectionState === 'closed') {
|
if (pc.connectionState === 'failed' || pc.connectionState === 'closed') {
|
||||||
this.activeOffers.delete(offerId)
|
this.activeOffers.delete(offerId!)
|
||||||
this.fillOffers() // Try to replace failed offer
|
this.fillOffers() // Try to replace failed offer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user