@xtr-dev/rondevu-server 0.2.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,11 +30,11 @@ Username Claiming → Service Publishing → Service Discovery → WebRTC Connec
30
30
 
31
31
  alice claims "alice" with Ed25519 signature
32
32
 
33
- alice publishes com.example.chat@1.0.0 → receives UUID abc123
33
+ alice publishes com.example.chat@1.0.0 with multiple offers → receives UUID abc123
34
34
 
35
- bob queries alice's services → gets UUID abc123
35
+ bob requests alice/com.example.chat@1.0.0 → gets compatible service with available offer
36
36
 
37
- bob connects to UUID abc123 → WebRTC connection established
37
+ WebRTC connection established via offer/answer exchange
38
38
  ```
39
39
 
40
40
  ## Quick Start
@@ -77,15 +77,28 @@ Generates a cryptographically random 128-bit peer ID.
77
77
  }
78
78
  ```
79
79
 
80
- ### Username Management
80
+ ### User Management (RESTful)
81
81
 
82
- #### `POST /usernames/claim`
82
+ #### `GET /users/:username`
83
+ Check username availability and claim status
84
+
85
+ **Response:**
86
+ ```json
87
+ {
88
+ "username": "alice",
89
+ "available": false,
90
+ "claimedAt": 1733404800000,
91
+ "expiresAt": 1765027200000,
92
+ "publicKey": "..."
93
+ }
94
+ ```
95
+
96
+ #### `POST /users/:username`
83
97
  Claim a username with cryptographic proof
84
98
 
85
99
  **Request:**
86
100
  ```json
87
101
  {
88
- "username": "alice",
89
102
  "publicKey": "base64-encoded-ed25519-public-key",
90
103
  "signature": "base64-encoded-signature",
91
104
  "message": "claim:alice:1733404800000"
@@ -107,46 +120,37 @@ Claim a username with cryptographic proof
107
120
  - Timestamp must be within 5 minutes (replay protection)
108
121
  - Expires after 365 days, auto-renewed on use
109
122
 
110
- #### `GET /usernames/:username`
111
- Check username availability and claim status
112
-
113
- **Response:**
114
- ```json
115
- {
116
- "username": "alice",
117
- "available": false,
118
- "claimedAt": 1733404800000,
119
- "expiresAt": 1765027200000,
120
- "publicKey": "..."
121
- }
122
- ```
123
+ #### `GET /users/:username/services/:fqn`
124
+ Get service by username and FQN with semver-compatible matching
123
125
 
124
- #### `GET /usernames/:username/services`
125
- List all services for a username (privacy-preserving)
126
+ **Semver Matching:**
127
+ - Requesting `chat@1.0.0` matches any `1.x.x` version
128
+ - Major version must match exactly (`chat@1.0.0` will NOT match `chat@2.0.0`)
129
+ - For major version 0, minor must also match (`0.1.0` will NOT match `0.2.0`)
130
+ - Returns the most recently published compatible version
126
131
 
127
132
  **Response:**
128
133
  ```json
129
134
  {
135
+ "uuid": "abc123",
136
+ "serviceId": "service-id",
130
137
  "username": "alice",
131
- "services": [
132
- {
133
- "uuid": "abc123",
134
- "isPublic": false
135
- },
136
- {
137
- "uuid": "def456",
138
- "isPublic": true,
139
- "serviceFqn": "com.example.public@1.0.0",
140
- "metadata": { "description": "Public service" }
141
- }
142
- ]
138
+ "serviceFqn": "chat.app@1.0.0",
139
+ "offerId": "offer-hash",
140
+ "sdp": "v=0...",
141
+ "isPublic": true,
142
+ "metadata": {},
143
+ "createdAt": 1733404800000,
144
+ "expiresAt": 1733405100000
143
145
  }
144
146
  ```
145
147
 
146
- ### Service Management
148
+ **Note:** Returns a single available offer from the service. If all offers are in use, returns 503.
149
+
150
+ ### Service Management (RESTful)
147
151
 
148
- #### `POST /services`
149
- Publish a service (requires authentication and username signature)
152
+ #### `POST /users/:username/services`
153
+ Publish a service with multiple offers (requires authentication and username signature)
150
154
 
151
155
  **Headers:**
152
156
  - `Authorization: Bearer {peerId}:{secret}`
@@ -154,9 +158,11 @@ Publish a service (requires authentication and username signature)
154
158
  **Request:**
155
159
  ```json
156
160
  {
157
- "username": "alice",
158
161
  "serviceFqn": "com.example.chat@1.0.0",
159
- "sdp": "v=0...",
162
+ "offers": [
163
+ { "sdp": "v=0..." },
164
+ { "sdp": "v=0..." }
165
+ ],
160
166
  "ttl": 300000,
161
167
  "isPublic": false,
162
168
  "metadata": { "description": "Chat service" },
@@ -165,12 +171,30 @@ Publish a service (requires authentication and username signature)
165
171
  }
166
172
  ```
167
173
 
168
- **Response:**
174
+ **Response (Full service details):**
169
175
  ```json
170
176
  {
171
- "serviceId": "uuid-v4",
172
177
  "uuid": "uuid-v4-for-index",
173
- "offerId": "offer-hash-id",
178
+ "serviceId": "uuid-v4",
179
+ "username": "alice",
180
+ "serviceFqn": "com.example.chat@1.0.0",
181
+ "offers": [
182
+ {
183
+ "offerId": "offer-hash-1",
184
+ "sdp": "v=0...",
185
+ "createdAt": 1733404800000,
186
+ "expiresAt": 1733405100000
187
+ },
188
+ {
189
+ "offerId": "offer-hash-2",
190
+ "sdp": "v=0...",
191
+ "createdAt": 1733404800000,
192
+ "expiresAt": 1733405100000
193
+ }
194
+ ],
195
+ "isPublic": false,
196
+ "metadata": { "description": "Chat service" },
197
+ "createdAt": 1733404800000,
174
198
  "expiresAt": 1733405100000
175
199
  }
176
200
  ```
@@ -203,7 +227,7 @@ Get service details by UUID
203
227
  }
204
228
  ```
205
229
 
206
- #### `DELETE /services/:serviceId`
230
+ #### `DELETE /users/:username/services/:fqn`
207
231
  Unpublish a service (requires authentication and ownership)
208
232
 
209
233
  **Headers:**
@@ -216,80 +240,91 @@ Unpublish a service (requires authentication and ownership)
216
240
  }
217
241
  ```
218
242
 
219
- ### Service Discovery
243
+ ### WebRTC Signaling (Service-Based)
220
244
 
221
- #### `POST /index/:username/query`
222
- Query a service by FQN
245
+ #### `POST /services/:uuid/answer`
246
+ Answer a service offer (requires authentication)
247
+
248
+ **Headers:**
249
+ - `Authorization: Bearer {peerId}:{secret}`
223
250
 
224
251
  **Request:**
225
252
  ```json
226
253
  {
227
- "serviceFqn": "com.example.chat@1.0.0"
254
+ "sdp": "v=0..."
228
255
  }
229
256
  ```
230
257
 
231
258
  **Response:**
232
259
  ```json
233
260
  {
234
- "uuid": "abc123",
235
- "allowed": true
261
+ "success": true,
262
+ "offerId": "offer-hash"
236
263
  }
237
264
  ```
238
265
 
239
- ### Offer Management (Low-level)
240
-
241
- #### `POST /offers`
242
- Create one or more offers (requires authentication)
266
+ #### `GET /services/:uuid/answer`
267
+ Get answer for a service (offerer polls this)
243
268
 
244
269
  **Headers:**
245
270
  - `Authorization: Bearer {peerId}:{secret}`
246
271
 
247
- **Request:**
272
+ **Response:**
248
273
  ```json
249
274
  {
250
- "offers": [
251
- {
252
- "sdp": "v=0...",
253
- "ttl": 300000
254
- }
255
- ]
275
+ "offerId": "offer-hash",
276
+ "answererId": "answerer-peer-id",
277
+ "sdp": "v=0...",
278
+ "answeredAt": 1733404800000
256
279
  }
257
280
  ```
258
281
 
259
- #### `GET /offers/mine`
260
- List all offers owned by authenticated peer
282
+ **Note:** Returns 404 if not yet answered
261
283
 
262
- #### `PUT /offers/:offerId/heartbeat`
263
- Update last_seen timestamp for an offer
284
+ #### `POST /services/:uuid/ice-candidates`
285
+ Post ICE candidates for a service (requires authentication)
264
286
 
265
- #### `DELETE /offers/:offerId`
266
- Delete a specific offer
267
-
268
- #### `POST /offers/:offerId/answer`
269
- Answer an offer (locks it to answerer)
287
+ **Headers:**
288
+ - `Authorization: Bearer {peerId}:{secret}`
270
289
 
271
290
  **Request:**
272
291
  ```json
273
292
  {
274
- "sdp": "v=0..."
293
+ "candidates": ["candidate:1 1 UDP..."],
294
+ "offerId": "optional-offer-id"
275
295
  }
276
296
  ```
277
297
 
278
- #### `GET /offers/answers`
279
- Poll for answers to your offers
298
+ **Response:**
299
+ ```json
300
+ {
301
+ "count": 1,
302
+ "offerId": "offer-hash"
303
+ }
304
+ ```
280
305
 
281
- #### `POST /offers/:offerId/ice-candidates`
282
- Post ICE candidates for an offer
306
+ **Note:** If `offerId` is omitted, the server will auto-detect the peer's offer
283
307
 
284
- **Request:**
308
+ #### `GET /services/:uuid/ice-candidates?since=1234567890&offerId=optional-offer-id`
309
+ Get ICE candidates from the other peer (requires authentication)
310
+
311
+ **Headers:**
312
+ - `Authorization: Bearer {peerId}:{secret}`
313
+
314
+ **Response:**
285
315
  ```json
286
316
  {
287
- "candidates": ["candidate:1 1 UDP..."]
317
+ "candidates": [
318
+ {
319
+ "candidate": "candidate:1 1 UDP...",
320
+ "createdAt": 1733404800000
321
+ }
322
+ ],
323
+ "offerId": "offer-hash"
288
324
  }
289
325
  ```
290
326
 
291
- #### `GET /offers/:offerId/ice-candidates?since=1234567890`
292
- Get ICE candidates from the other peer
327
+ **Note:** Returns candidates from the opposite role (offerer gets answerer candidates and vice versa)
293
328
 
294
329
  ## Configuration
295
330
 
@@ -321,11 +356,19 @@ Environment variables:
321
356
  - `id` (PK): Service ID (UUID)
322
357
  - `username` (FK): Owner username
323
358
  - `service_fqn`: Fully qualified name (com.example.chat@1.0.0)
324
- - `offer_id` (FK): WebRTC offer ID
325
359
  - `is_public`: Public/private flag
326
360
  - `metadata`: JSON metadata
327
361
  - `created_at`, `expires_at`: Timestamps
328
362
 
363
+ ### offers
364
+ - `id` (PK): Offer ID (hash of SDP)
365
+ - `peer_id` (FK): Owner peer ID
366
+ - `service_id` (FK): Optional link to service (null for standalone offers)
367
+ - `sdp`: WebRTC offer SDP
368
+ - `answerer_peer_id`: Peer ID of answerer (null until answered)
369
+ - `answer_sdp`: WebRTC answer SDP (null until answered)
370
+ - `created_at`, `expires_at`, `last_seen`: Timestamps
371
+
329
372
  ### service_index (privacy layer)
330
373
  - `uuid` (PK): Random UUID for discovery
331
374
  - `service_id` (FK): Links to service