@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 +121 -78
- package/dist/index.js +318 -220
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
- package/src/app.ts +314 -272
- package/src/config.ts +1 -3
- package/src/crypto.ts +54 -0
- package/src/index.ts +0 -1
- package/src/storage/d1.ts +54 -7
- package/src/storage/hash-id.ts +4 -9
- package/src/storage/sqlite.ts +66 -15
- package/src/storage/types.ts +43 -10
- package/src/worker.ts +1 -3
- package/src/bloom.ts +0 -66
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
|
|
35
|
+
bob requests alice/com.example.chat@1.0.0 → gets compatible service with available offer
|
|
36
36
|
↓
|
|
37
|
-
|
|
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
|
-
###
|
|
80
|
+
### User Management (RESTful)
|
|
81
81
|
|
|
82
|
-
#### `
|
|
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 /
|
|
111
|
-
|
|
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
|
-
|
|
125
|
-
|
|
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
|
-
"
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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/:
|
|
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
|
|
243
|
+
### WebRTC Signaling (Service-Based)
|
|
220
244
|
|
|
221
|
-
#### `POST /
|
|
222
|
-
|
|
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
|
-
"
|
|
254
|
+
"sdp": "v=0..."
|
|
228
255
|
}
|
|
229
256
|
```
|
|
230
257
|
|
|
231
258
|
**Response:**
|
|
232
259
|
```json
|
|
233
260
|
{
|
|
234
|
-
"
|
|
235
|
-
"
|
|
261
|
+
"success": true,
|
|
262
|
+
"offerId": "offer-hash"
|
|
236
263
|
}
|
|
237
264
|
```
|
|
238
265
|
|
|
239
|
-
|
|
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
|
-
**
|
|
272
|
+
**Response:**
|
|
248
273
|
```json
|
|
249
274
|
{
|
|
250
|
-
"
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
260
|
-
List all offers owned by authenticated peer
|
|
282
|
+
**Note:** Returns 404 if not yet answered
|
|
261
283
|
|
|
262
|
-
#### `
|
|
263
|
-
|
|
284
|
+
#### `POST /services/:uuid/ice-candidates`
|
|
285
|
+
Post ICE candidates for a service (requires authentication)
|
|
264
286
|
|
|
265
|
-
|
|
266
|
-
|
|
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
|
-
"
|
|
293
|
+
"candidates": ["candidate:1 1 UDP..."],
|
|
294
|
+
"offerId": "optional-offer-id"
|
|
275
295
|
}
|
|
276
296
|
```
|
|
277
297
|
|
|
278
|
-
|
|
279
|
-
|
|
298
|
+
**Response:**
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"count": 1,
|
|
302
|
+
"offerId": "offer-hash"
|
|
303
|
+
}
|
|
304
|
+
```
|
|
280
305
|
|
|
281
|
-
|
|
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
|
-
|
|
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": [
|
|
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
|
-
|
|
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
|