@xtr-dev/rondevu-server 0.1.5 → 0.2.1
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 +217 -69
- package/dist/index.js +1070 -368
- package/dist/index.js.map +4 -4
- package/package.json +3 -2
- package/src/app.ts +339 -271
- package/src/crypto.ts +170 -0
- package/src/storage/d1.ts +295 -119
- package/src/storage/sqlite.ts +309 -107
- package/src/storage/types.ts +159 -29
package/src/storage/types.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Represents a WebRTC signaling offer
|
|
2
|
+
* Represents a WebRTC signaling offer (no topics)
|
|
3
3
|
*/
|
|
4
4
|
export interface Offer {
|
|
5
5
|
id: string;
|
|
6
6
|
peerId: string;
|
|
7
7
|
sdp: string;
|
|
8
|
-
topics: string[];
|
|
9
8
|
createdAt: number;
|
|
10
9
|
expiresAt: number;
|
|
11
10
|
lastSeen: number;
|
|
@@ -29,14 +28,6 @@ export interface IceCandidate {
|
|
|
29
28
|
createdAt: number;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
/**
|
|
33
|
-
* Represents a topic with active peer count
|
|
34
|
-
*/
|
|
35
|
-
export interface TopicInfo {
|
|
36
|
-
topic: string;
|
|
37
|
-
activePeers: number;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
31
|
/**
|
|
41
32
|
* Request to create a new offer
|
|
42
33
|
*/
|
|
@@ -44,17 +35,88 @@ export interface CreateOfferRequest {
|
|
|
44
35
|
id?: string;
|
|
45
36
|
peerId: string;
|
|
46
37
|
sdp: string;
|
|
47
|
-
topics: string[];
|
|
48
38
|
expiresAt: number;
|
|
49
39
|
secret?: string;
|
|
50
40
|
info?: string;
|
|
51
41
|
}
|
|
52
42
|
|
|
53
43
|
/**
|
|
54
|
-
*
|
|
55
|
-
|
|
44
|
+
* Represents a claimed username with cryptographic proof
|
|
45
|
+
*/
|
|
46
|
+
export interface Username {
|
|
47
|
+
username: string;
|
|
48
|
+
publicKey: string; // Base64-encoded Ed25519 public key
|
|
49
|
+
claimedAt: number;
|
|
50
|
+
expiresAt: number; // 365 days from claim/last use
|
|
51
|
+
lastUsed: number;
|
|
52
|
+
metadata?: string; // JSON optional user metadata
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Request to claim a username
|
|
57
|
+
*/
|
|
58
|
+
export interface ClaimUsernameRequest {
|
|
59
|
+
username: string;
|
|
60
|
+
publicKey: string;
|
|
61
|
+
signature: string;
|
|
62
|
+
message: string; // "claim:{username}:{timestamp}"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Represents a published service
|
|
67
|
+
*/
|
|
68
|
+
export interface Service {
|
|
69
|
+
id: string; // UUID v4
|
|
70
|
+
username: string;
|
|
71
|
+
serviceFqn: string; // com.example.chat@1.0.0
|
|
72
|
+
offerId: string; // Links to offers table
|
|
73
|
+
createdAt: number;
|
|
74
|
+
expiresAt: number;
|
|
75
|
+
isPublic: boolean;
|
|
76
|
+
metadata?: string; // JSON service description
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Request to create a service
|
|
81
|
+
*/
|
|
82
|
+
export interface CreateServiceRequest {
|
|
83
|
+
username: string;
|
|
84
|
+
serviceFqn: string;
|
|
85
|
+
offerId: string;
|
|
86
|
+
expiresAt: number;
|
|
87
|
+
isPublic?: boolean;
|
|
88
|
+
metadata?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Represents a service index entry (privacy layer)
|
|
93
|
+
*/
|
|
94
|
+
export interface ServiceIndex {
|
|
95
|
+
uuid: string; // Random UUID for privacy
|
|
96
|
+
serviceId: string;
|
|
97
|
+
username: string;
|
|
98
|
+
serviceFqn: string;
|
|
99
|
+
createdAt: number;
|
|
100
|
+
expiresAt: number;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Service info for discovery (privacy-aware)
|
|
105
|
+
*/
|
|
106
|
+
export interface ServiceInfo {
|
|
107
|
+
uuid: string;
|
|
108
|
+
isPublic: boolean;
|
|
109
|
+
serviceFqn?: string; // Only present if public
|
|
110
|
+
metadata?: string; // Only present if public
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Storage interface for rondevu DNS-like system
|
|
115
|
+
* Implementations can use different backends (SQLite, D1, etc.)
|
|
56
116
|
*/
|
|
57
117
|
export interface Storage {
|
|
118
|
+
// ===== Offer Management =====
|
|
119
|
+
|
|
58
120
|
/**
|
|
59
121
|
* Creates one or more offers
|
|
60
122
|
* @param offers Array of offer creation requests
|
|
@@ -62,14 +124,6 @@ export interface Storage {
|
|
|
62
124
|
*/
|
|
63
125
|
createOffers(offers: CreateOfferRequest[]): Promise<Offer[]>;
|
|
64
126
|
|
|
65
|
-
/**
|
|
66
|
-
* Retrieves offers by topic with optional peer ID exclusion
|
|
67
|
-
* @param topic Topic to search for
|
|
68
|
-
* @param excludePeerIds Optional array of peer IDs to exclude
|
|
69
|
-
* @returns Array of offers matching the topic
|
|
70
|
-
*/
|
|
71
|
-
getOffersByTopic(topic: string, excludePeerIds?: string[]): Promise<Offer[]>;
|
|
72
|
-
|
|
73
127
|
/**
|
|
74
128
|
* Retrieves all offers from a specific peer
|
|
75
129
|
* @param peerId Peer identifier
|
|
@@ -119,6 +173,8 @@ export interface Storage {
|
|
|
119
173
|
*/
|
|
120
174
|
getAnsweredOffers(offererPeerId: string): Promise<Offer[]>;
|
|
121
175
|
|
|
176
|
+
// ===== ICE Candidate Management =====
|
|
177
|
+
|
|
122
178
|
/**
|
|
123
179
|
* Adds ICE candidates for an offer
|
|
124
180
|
* @param offerId Offer identifier
|
|
@@ -147,18 +203,92 @@ export interface Storage {
|
|
|
147
203
|
since?: number
|
|
148
204
|
): Promise<IceCandidate[]>;
|
|
149
205
|
|
|
206
|
+
// ===== Username Management =====
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Claims a username (or refreshes expiry if already owned)
|
|
210
|
+
* @param request Username claim request with signature
|
|
211
|
+
* @returns Created/updated username record
|
|
212
|
+
*/
|
|
213
|
+
claimUsername(request: ClaimUsernameRequest): Promise<Username>;
|
|
214
|
+
|
|
150
215
|
/**
|
|
151
|
-
*
|
|
152
|
-
* @param
|
|
153
|
-
* @
|
|
154
|
-
* @param startsWith Optional prefix filter - only return topics starting with this string
|
|
155
|
-
* @returns Object with topics array and total count
|
|
216
|
+
* Gets a username record
|
|
217
|
+
* @param username Username to look up
|
|
218
|
+
* @returns Username record if claimed, null otherwise
|
|
156
219
|
*/
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
220
|
+
getUsername(username: string): Promise<Username | null>;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Updates the last_used timestamp for a username (extends expiry)
|
|
224
|
+
* @param username Username to update
|
|
225
|
+
* @returns true if updated, false if not found
|
|
226
|
+
*/
|
|
227
|
+
touchUsername(username: string): Promise<boolean>;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Deletes all expired usernames
|
|
231
|
+
* @param now Current timestamp
|
|
232
|
+
* @returns Number of usernames deleted
|
|
233
|
+
*/
|
|
234
|
+
deleteExpiredUsernames(now: number): Promise<number>;
|
|
235
|
+
|
|
236
|
+
// ===== Service Management =====
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Creates a new service
|
|
240
|
+
* @param request Service creation request
|
|
241
|
+
* @returns Created service with generated ID and index UUID
|
|
242
|
+
*/
|
|
243
|
+
createService(request: CreateServiceRequest): Promise<{
|
|
244
|
+
service: Service;
|
|
245
|
+
indexUuid: string;
|
|
160
246
|
}>;
|
|
161
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Gets a service by its service ID
|
|
250
|
+
* @param serviceId Service ID
|
|
251
|
+
* @returns Service if found, null otherwise
|
|
252
|
+
*/
|
|
253
|
+
getServiceById(serviceId: string): Promise<Service | null>;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Gets a service by its index UUID
|
|
257
|
+
* @param uuid Index UUID
|
|
258
|
+
* @returns Service if found, null otherwise
|
|
259
|
+
*/
|
|
260
|
+
getServiceByUuid(uuid: string): Promise<Service | null>;
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Lists all services for a username (with privacy filtering)
|
|
264
|
+
* @param username Username to query
|
|
265
|
+
* @returns Array of service info (UUIDs only for private services)
|
|
266
|
+
*/
|
|
267
|
+
listServicesForUsername(username: string): Promise<ServiceInfo[]>;
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Queries a service by username and FQN
|
|
271
|
+
* @param username Username
|
|
272
|
+
* @param serviceFqn Service FQN
|
|
273
|
+
* @returns Service index UUID if found, null otherwise
|
|
274
|
+
*/
|
|
275
|
+
queryService(username: string, serviceFqn: string): Promise<string | null>;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Deletes a service (with ownership verification)
|
|
279
|
+
* @param serviceId Service ID
|
|
280
|
+
* @param username Owner username (for verification)
|
|
281
|
+
* @returns true if deleted, false if not found or not owned
|
|
282
|
+
*/
|
|
283
|
+
deleteService(serviceId: string, username: string): Promise<boolean>;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Deletes all expired services
|
|
287
|
+
* @param now Current timestamp
|
|
288
|
+
* @returns Number of services deleted
|
|
289
|
+
*/
|
|
290
|
+
deleteExpiredServices(now: number): Promise<number>;
|
|
291
|
+
|
|
162
292
|
/**
|
|
163
293
|
* Closes the storage connection and releases resources
|
|
164
294
|
*/
|