@xtr-dev/rondevu-server 0.5.10 → 0.5.12
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/dist/index.js +34 -21
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/src/config.ts +2 -2
- package/src/rpc.ts +8 -2
- package/src/storage/d1.ts +8 -4
- package/src/storage/memory.ts +3 -1
- package/src/storage/mysql.ts +7 -3
- package/src/storage/postgres.ts +9 -5
- package/src/storage/sqlite.ts +8 -4
- package/src/storage/types.ts +3 -1
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -113,8 +113,8 @@ export function loadConfig(): Config {
|
|
|
113
113
|
timestampMaxFuture: parsePositiveInt(process.env.TIMESTAMP_MAX_FUTURE, '60000', 'TIMESTAMP_MAX_FUTURE', 1000), // Min 1 second
|
|
114
114
|
masterEncryptionKey,
|
|
115
115
|
// Resource limits
|
|
116
|
-
maxOffersPerUser: parsePositiveInt(process.env.MAX_OFFERS_PER_USER, '
|
|
117
|
-
maxTotalOffers: parsePositiveInt(process.env.MAX_TOTAL_OFFERS, '
|
|
116
|
+
maxOffersPerUser: parsePositiveInt(process.env.MAX_OFFERS_PER_USER, '1000', 'MAX_OFFERS_PER_USER', 1),
|
|
117
|
+
maxTotalOffers: parsePositiveInt(process.env.MAX_TOTAL_OFFERS, '100000', 'MAX_TOTAL_OFFERS', 1),
|
|
118
118
|
maxTotalCredentials: parsePositiveInt(process.env.MAX_TOTAL_CREDENTIALS, '50000', 'MAX_TOTAL_CREDENTIALS', 1),
|
|
119
119
|
maxIceCandidatesPerOffer: parsePositiveInt(process.env.MAX_ICE_CANDIDATES_PER_OFFER, '50', 'MAX_ICE_CANDIDATES_PER_OFFER', 1),
|
|
120
120
|
credentialsPerIpPerSecond: parsePositiveInt(process.env.CREDENTIALS_PER_IP_PER_SECOND, '5', 'CREDENTIALS_PER_IP_PER_SECOND', 1),
|
package/src/rpc.ts
CHANGED
|
@@ -168,6 +168,7 @@ export interface DeleteOfferParams {
|
|
|
168
168
|
export interface AnswerOfferParams {
|
|
169
169
|
offerId: string;
|
|
170
170
|
sdp: string;
|
|
171
|
+
matchedTags?: string[]; // Tags the answerer searched for to find this offer
|
|
171
172
|
}
|
|
172
173
|
|
|
173
174
|
export interface GetOfferAnswerParams {
|
|
@@ -565,7 +566,7 @@ const handlers: Record<string, RpcHandler> = {
|
|
|
565
566
|
* Answer an offer
|
|
566
567
|
*/
|
|
567
568
|
async answerOffer(params: AnswerOfferParams, name, timestamp, signature, storage, config, request: RpcRequest) {
|
|
568
|
-
const { offerId, sdp } = params;
|
|
569
|
+
const { offerId, sdp, matchedTags } = params;
|
|
569
570
|
|
|
570
571
|
// Validate input parameters
|
|
571
572
|
validateStringParam(offerId, 'offerId');
|
|
@@ -582,6 +583,11 @@ const handlers: Record<string, RpcHandler> = {
|
|
|
582
583
|
throw new RpcError(ErrorCodes.SDP_TOO_LARGE, `SDP too large (max ${config.maxSdpSize} bytes)`);
|
|
583
584
|
}
|
|
584
585
|
|
|
586
|
+
// Validate matchedTags if provided
|
|
587
|
+
if (matchedTags !== undefined && !Array.isArray(matchedTags)) {
|
|
588
|
+
throw new RpcError(ErrorCodes.INVALID_PARAMS, 'matchedTags must be an array');
|
|
589
|
+
}
|
|
590
|
+
|
|
585
591
|
const offer = await storage.getOfferById(offerId);
|
|
586
592
|
if (!offer) {
|
|
587
593
|
throw new RpcError(ErrorCodes.OFFER_NOT_FOUND, 'Offer not found');
|
|
@@ -591,7 +597,7 @@ const handlers: Record<string, RpcHandler> = {
|
|
|
591
597
|
throw new RpcError(ErrorCodes.OFFER_ALREADY_ANSWERED, 'Offer already answered');
|
|
592
598
|
}
|
|
593
599
|
|
|
594
|
-
await storage.answerOffer(offerId, name, sdp);
|
|
600
|
+
await storage.answerOffer(offerId, name, sdp, matchedTags);
|
|
595
601
|
|
|
596
602
|
return { success: true, offerId };
|
|
597
603
|
},
|
package/src/storage/d1.ts
CHANGED
|
@@ -45,7 +45,8 @@ export class D1Storage implements Storage {
|
|
|
45
45
|
last_seen INTEGER NOT NULL,
|
|
46
46
|
answerer_username TEXT,
|
|
47
47
|
answer_sdp TEXT,
|
|
48
|
-
answered_at INTEGER
|
|
48
|
+
answered_at INTEGER,
|
|
49
|
+
matched_tags TEXT
|
|
49
50
|
);
|
|
50
51
|
|
|
51
52
|
CREATE INDEX IF NOT EXISTS idx_offers_username ON offers(username);
|
|
@@ -176,7 +177,8 @@ export class D1Storage implements Storage {
|
|
|
176
177
|
async answerOffer(
|
|
177
178
|
offerId: string,
|
|
178
179
|
answererUsername: string,
|
|
179
|
-
answerSdp: string
|
|
180
|
+
answerSdp: string,
|
|
181
|
+
matchedTags?: string[]
|
|
180
182
|
): Promise<{ success: boolean; error?: string }> {
|
|
181
183
|
// Check if offer exists and is not expired
|
|
182
184
|
const offer = await this.getOfferById(offerId);
|
|
@@ -197,11 +199,12 @@ export class D1Storage implements Storage {
|
|
|
197
199
|
}
|
|
198
200
|
|
|
199
201
|
// Update offer with answer
|
|
202
|
+
const matchedTagsJson = matchedTags ? JSON.stringify(matchedTags) : null;
|
|
200
203
|
const result = await this.db.prepare(`
|
|
201
204
|
UPDATE offers
|
|
202
|
-
SET answerer_username = ?, answer_sdp = ?, answered_at = ?
|
|
205
|
+
SET answerer_username = ?, answer_sdp = ?, answered_at = ?, matched_tags = ?
|
|
203
206
|
WHERE id = ? AND answerer_username IS NULL
|
|
204
|
-
`).bind(answererUsername, answerSdp, Date.now(), offerId).run();
|
|
207
|
+
`).bind(answererUsername, answerSdp, Date.now(), matchedTagsJson, offerId).run();
|
|
205
208
|
|
|
206
209
|
if ((result.meta.changes || 0) === 0) {
|
|
207
210
|
return {
|
|
@@ -674,6 +677,7 @@ export class D1Storage implements Storage {
|
|
|
674
677
|
answererUsername: row.answerer_username || undefined,
|
|
675
678
|
answerSdp: row.answer_sdp || undefined,
|
|
676
679
|
answeredAt: row.answered_at || undefined,
|
|
680
|
+
matchedTags: row.matched_tags ? JSON.parse(row.matched_tags) : undefined,
|
|
677
681
|
};
|
|
678
682
|
}
|
|
679
683
|
}
|
package/src/storage/memory.ts
CHANGED
|
@@ -143,7 +143,8 @@ export class MemoryStorage implements Storage {
|
|
|
143
143
|
async answerOffer(
|
|
144
144
|
offerId: string,
|
|
145
145
|
answererUsername: string,
|
|
146
|
-
answerSdp: string
|
|
146
|
+
answerSdp: string,
|
|
147
|
+
matchedTags?: string[]
|
|
147
148
|
): Promise<{ success: boolean; error?: string }> {
|
|
148
149
|
const offer = await this.getOfferById(offerId);
|
|
149
150
|
|
|
@@ -160,6 +161,7 @@ export class MemoryStorage implements Storage {
|
|
|
160
161
|
offer.answererUsername = answererUsername;
|
|
161
162
|
offer.answerSdp = answerSdp;
|
|
162
163
|
offer.answeredAt = now;
|
|
164
|
+
offer.matchedTags = matchedTags;
|
|
163
165
|
|
|
164
166
|
// Update answerer index
|
|
165
167
|
if (!this.offersByAnswerer.has(answererUsername)) {
|
package/src/storage/mysql.ts
CHANGED
|
@@ -64,6 +64,7 @@ export class MySQLStorage implements Storage {
|
|
|
64
64
|
answerer_username VARCHAR(32),
|
|
65
65
|
answer_sdp MEDIUMTEXT,
|
|
66
66
|
answered_at BIGINT,
|
|
67
|
+
matched_tags JSON,
|
|
67
68
|
INDEX idx_offers_username (username),
|
|
68
69
|
INDEX idx_offers_expires (expires_at),
|
|
69
70
|
INDEX idx_offers_last_seen (last_seen),
|
|
@@ -196,7 +197,8 @@ export class MySQLStorage implements Storage {
|
|
|
196
197
|
async answerOffer(
|
|
197
198
|
offerId: string,
|
|
198
199
|
answererUsername: string,
|
|
199
|
-
answerSdp: string
|
|
200
|
+
answerSdp: string,
|
|
201
|
+
matchedTags?: string[]
|
|
200
202
|
): Promise<{ success: boolean; error?: string }> {
|
|
201
203
|
const offer = await this.getOfferById(offerId);
|
|
202
204
|
|
|
@@ -208,10 +210,11 @@ export class MySQLStorage implements Storage {
|
|
|
208
210
|
return { success: false, error: 'Offer already answered' };
|
|
209
211
|
}
|
|
210
212
|
|
|
213
|
+
const matchedTagsJson = matchedTags ? JSON.stringify(matchedTags) : null;
|
|
211
214
|
const [result] = await this.pool.query<ResultSetHeader>(
|
|
212
|
-
`UPDATE offers SET answerer_username = ?, answer_sdp = ?, answered_at = ?
|
|
215
|
+
`UPDATE offers SET answerer_username = ?, answer_sdp = ?, answered_at = ?, matched_tags = ?
|
|
213
216
|
WHERE id = ? AND answerer_username IS NULL`,
|
|
214
|
-
[answererUsername, answerSdp, Date.now(), offerId]
|
|
217
|
+
[answererUsername, answerSdp, Date.now(), matchedTagsJson, offerId]
|
|
215
218
|
);
|
|
216
219
|
|
|
217
220
|
if (result.affectedRows === 0) {
|
|
@@ -600,6 +603,7 @@ export class MySQLStorage implements Storage {
|
|
|
600
603
|
answererUsername: row.answerer_username || undefined,
|
|
601
604
|
answerSdp: row.answer_sdp || undefined,
|
|
602
605
|
answeredAt: row.answered_at ? Number(row.answered_at) : undefined,
|
|
606
|
+
matchedTags: row.matched_tags ? (typeof row.matched_tags === 'string' ? JSON.parse(row.matched_tags) : row.matched_tags) : undefined,
|
|
603
607
|
};
|
|
604
608
|
}
|
|
605
609
|
|
package/src/storage/postgres.ts
CHANGED
|
@@ -61,7 +61,8 @@ export class PostgreSQLStorage implements Storage {
|
|
|
61
61
|
last_seen BIGINT NOT NULL,
|
|
62
62
|
answerer_username VARCHAR(32),
|
|
63
63
|
answer_sdp TEXT,
|
|
64
|
-
answered_at BIGINT
|
|
64
|
+
answered_at BIGINT,
|
|
65
|
+
matched_tags JSONB
|
|
65
66
|
)
|
|
66
67
|
`);
|
|
67
68
|
|
|
@@ -199,7 +200,8 @@ export class PostgreSQLStorage implements Storage {
|
|
|
199
200
|
async answerOffer(
|
|
200
201
|
offerId: string,
|
|
201
202
|
answererUsername: string,
|
|
202
|
-
answerSdp: string
|
|
203
|
+
answerSdp: string,
|
|
204
|
+
matchedTags?: string[]
|
|
203
205
|
): Promise<{ success: boolean; error?: string }> {
|
|
204
206
|
const offer = await this.getOfferById(offerId);
|
|
205
207
|
|
|
@@ -211,10 +213,11 @@ export class PostgreSQLStorage implements Storage {
|
|
|
211
213
|
return { success: false, error: 'Offer already answered' };
|
|
212
214
|
}
|
|
213
215
|
|
|
216
|
+
const matchedTagsJson = matchedTags ? JSON.stringify(matchedTags) : null;
|
|
214
217
|
const result = await this.pool.query(
|
|
215
|
-
`UPDATE offers SET answerer_username = $1, answer_sdp = $2, answered_at = $3
|
|
216
|
-
WHERE id = $
|
|
217
|
-
[answererUsername, answerSdp, Date.now(), offerId]
|
|
218
|
+
`UPDATE offers SET answerer_username = $1, answer_sdp = $2, answered_at = $3, matched_tags = $4
|
|
219
|
+
WHERE id = $5 AND answerer_username IS NULL`,
|
|
220
|
+
[answererUsername, answerSdp, Date.now(), matchedTagsJson, offerId]
|
|
218
221
|
);
|
|
219
222
|
|
|
220
223
|
if ((result.rowCount ?? 0) === 0) {
|
|
@@ -607,6 +610,7 @@ export class PostgreSQLStorage implements Storage {
|
|
|
607
610
|
answererUsername: row.answerer_username || undefined,
|
|
608
611
|
answerSdp: row.answer_sdp || undefined,
|
|
609
612
|
answeredAt: row.answered_at ? Number(row.answered_at) : undefined,
|
|
613
|
+
matchedTags: row.matched_tags || undefined,
|
|
610
614
|
};
|
|
611
615
|
}
|
|
612
616
|
|
package/src/storage/sqlite.ts
CHANGED
|
@@ -46,7 +46,8 @@ export class SQLiteStorage implements Storage {
|
|
|
46
46
|
last_seen INTEGER NOT NULL,
|
|
47
47
|
answerer_username TEXT,
|
|
48
48
|
answer_sdp TEXT,
|
|
49
|
-
answered_at INTEGER
|
|
49
|
+
answered_at INTEGER,
|
|
50
|
+
matched_tags TEXT
|
|
50
51
|
);
|
|
51
52
|
|
|
52
53
|
CREATE INDEX IF NOT EXISTS idx_offers_username ON offers(username);
|
|
@@ -199,7 +200,8 @@ export class SQLiteStorage implements Storage {
|
|
|
199
200
|
async answerOffer(
|
|
200
201
|
offerId: string,
|
|
201
202
|
answererUsername: string,
|
|
202
|
-
answerSdp: string
|
|
203
|
+
answerSdp: string,
|
|
204
|
+
matchedTags?: string[]
|
|
203
205
|
): Promise<{ success: boolean; error?: string }> {
|
|
204
206
|
// Check if offer exists and is not expired
|
|
205
207
|
const offer = await this.getOfferById(offerId);
|
|
@@ -222,11 +224,12 @@ export class SQLiteStorage implements Storage {
|
|
|
222
224
|
// Update offer with answer
|
|
223
225
|
const stmt = this.db.prepare(`
|
|
224
226
|
UPDATE offers
|
|
225
|
-
SET answerer_username = ?, answer_sdp = ?, answered_at = ?
|
|
227
|
+
SET answerer_username = ?, answer_sdp = ?, answered_at = ?, matched_tags = ?
|
|
226
228
|
WHERE id = ? AND answerer_username IS NULL
|
|
227
229
|
`);
|
|
228
230
|
|
|
229
|
-
const
|
|
231
|
+
const matchedTagsJson = matchedTags ? JSON.stringify(matchedTags) : null;
|
|
232
|
+
const result = stmt.run(answererUsername, answerSdp, Date.now(), matchedTagsJson, offerId);
|
|
230
233
|
|
|
231
234
|
if (result.changes === 0) {
|
|
232
235
|
return {
|
|
@@ -681,6 +684,7 @@ export class SQLiteStorage implements Storage {
|
|
|
681
684
|
answererUsername: row.answerer_username || undefined,
|
|
682
685
|
answerSdp: row.answer_sdp || undefined,
|
|
683
686
|
answeredAt: row.answered_at || undefined,
|
|
687
|
+
matchedTags: row.matched_tags ? JSON.parse(row.matched_tags) : undefined,
|
|
684
688
|
};
|
|
685
689
|
}
|
|
686
690
|
}
|
package/src/storage/types.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface Offer {
|
|
|
12
12
|
answererUsername?: string;
|
|
13
13
|
answerSdp?: string;
|
|
14
14
|
answeredAt?: number;
|
|
15
|
+
matchedTags?: string[]; // Tags the answerer searched for to find this offer
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -118,9 +119,10 @@ export interface Storage {
|
|
|
118
119
|
* @param offerId Offer identifier
|
|
119
120
|
* @param answererUsername Answerer's username
|
|
120
121
|
* @param answerSdp WebRTC answer SDP
|
|
122
|
+
* @param matchedTags Optional tags the answerer searched for to find this offer
|
|
121
123
|
* @returns Success status and optional error message
|
|
122
124
|
*/
|
|
123
|
-
answerOffer(offerId: string, answererUsername: string, answerSdp: string): Promise<{
|
|
125
|
+
answerOffer(offerId: string, answererUsername: string, answerSdp: string, matchedTags?: string[]): Promise<{
|
|
124
126
|
success: boolean;
|
|
125
127
|
error?: string;
|
|
126
128
|
}>;
|