@webex/internal-plugin-llm 3.12.0-next.19 → 3.12.0-next.20
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 +2 -2
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/llm.js +241 -39
- package/dist/llm.js.map +1 -1
- package/dist/llm.types.js.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +1 -0
- package/src/index.ts +1 -0
- package/src/llm.ts +261 -41
- package/src/llm.types.ts +42 -8
- package/test/unit/spec/llm.js +227 -20
package/src/llm.types.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export enum DataChannelTokenType {
|
|
2
|
+
Default = 'llm-default-session',
|
|
3
|
+
PracticeSession = 'llm-practice-session',
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
type DataChannelTokenKey = DataChannelTokenType | string;
|
|
7
|
+
|
|
1
8
|
interface ILLMChannel {
|
|
2
9
|
registerAndConnect: (
|
|
3
10
|
locusUrl: string,
|
|
@@ -9,10 +16,43 @@ interface ILLMChannel {
|
|
|
9
16
|
getBinding: (sessionId?: string) => string;
|
|
10
17
|
getLocusUrl: (sessionId?: string) => string;
|
|
11
18
|
getDatachannelUrl: (sessionId?: string) => string;
|
|
12
|
-
disconnectLLM: (
|
|
19
|
+
disconnectLLM: (
|
|
20
|
+
options: {code: number; reason: string},
|
|
21
|
+
sessionId?: string,
|
|
22
|
+
ownerMeetingId?: string
|
|
23
|
+
) => Promise<boolean>;
|
|
13
24
|
disconnectAllLLM: (options?: {code: number; reason: string}) => Promise<void>;
|
|
14
25
|
setOwnerMeetingId: (ownerMeetingId: string | undefined, sessionId?: string) => void;
|
|
15
26
|
getOwnerMeetingId: (sessionId?: string) => string | undefined;
|
|
27
|
+
resolveSessionOwnership: (
|
|
28
|
+
ownerMeetingId?: string,
|
|
29
|
+
sessionId?: string
|
|
30
|
+
) => {
|
|
31
|
+
currentOwner: string | undefined;
|
|
32
|
+
isOwner: boolean;
|
|
33
|
+
};
|
|
34
|
+
getDatachannelToken: (
|
|
35
|
+
tokenKey?: DataChannelTokenKey,
|
|
36
|
+
ownerMeetingId?: string
|
|
37
|
+
) => string | undefined;
|
|
38
|
+
setDatachannelToken: (
|
|
39
|
+
datachannelToken: string,
|
|
40
|
+
tokenKey?: DataChannelTokenKey,
|
|
41
|
+
ownerMeetingId?: string
|
|
42
|
+
) => void;
|
|
43
|
+
clearDatachannelToken: (tokenKey: DataChannelTokenKey, ownerMeetingId: string) => void;
|
|
44
|
+
setRefreshHandler: (
|
|
45
|
+
handler: () => Promise<{
|
|
46
|
+
body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};
|
|
47
|
+
}>,
|
|
48
|
+
sessionId?: string,
|
|
49
|
+
ownerMeetingId?: string
|
|
50
|
+
) => void;
|
|
51
|
+
refreshDataChannelToken: (sessionId?: string) => Promise<{
|
|
52
|
+
body: {datachannelToken: string; datachannelTokenType: DataChannelTokenType};
|
|
53
|
+
} | null>;
|
|
54
|
+
getLocusUrlByDatachannelUrl: (requestUrl: string) => string | undefined;
|
|
55
|
+
getSessionIdByDatachannelUrl: (requestUrl: string) => string | undefined;
|
|
16
56
|
getAllConnections: () => Map<
|
|
17
57
|
string,
|
|
18
58
|
{
|
|
@@ -20,16 +60,10 @@ interface ILLMChannel {
|
|
|
20
60
|
binding?: string;
|
|
21
61
|
locusUrl?: string;
|
|
22
62
|
datachannelUrl?: string;
|
|
23
|
-
datachannelToken?: string;
|
|
24
63
|
ownerMeetingId?: string;
|
|
25
64
|
}
|
|
26
65
|
>;
|
|
27
66
|
}
|
|
28
67
|
|
|
29
|
-
export enum DataChannelTokenType {
|
|
30
|
-
Default = 'llm-default-session',
|
|
31
|
-
PracticeSession = 'llm-practice-session',
|
|
32
|
-
}
|
|
33
|
-
|
|
34
68
|
// eslint-disable-next-line import/prefer-default-export
|
|
35
|
-
export type {ILLMChannel};
|
|
69
|
+
export type {ILLMChannel, DataChannelTokenKey};
|
package/test/unit/spec/llm.js
CHANGED
|
@@ -3,6 +3,7 @@ import {assert} from '@webex/test-helper-chai';
|
|
|
3
3
|
import sinon from 'sinon';
|
|
4
4
|
import Mercury from '@webex/internal-plugin-mercury';
|
|
5
5
|
import LLMService from '@webex/internal-plugin-llm';
|
|
6
|
+
import LLMChannel from '@webex/internal-plugin-llm/src/llm';
|
|
6
7
|
|
|
7
8
|
describe('plugin-llm', () => {
|
|
8
9
|
const locusUrl = 'locusUrl';
|
|
@@ -277,23 +278,27 @@ describe('plugin-llm', () => {
|
|
|
277
278
|
instance = {
|
|
278
279
|
disconnect: jest.fn(() => Promise.resolve()),
|
|
279
280
|
connections: new Map([
|
|
280
|
-
['llm-default-session', { foo: 'bar' }],
|
|
281
|
+
['llm-default-session', { foo: 'bar', datachannelToken: 'session-token' }],
|
|
281
282
|
]),
|
|
282
|
-
datachannelTokens: {
|
|
283
|
-
'llm-default-session': 'session-token',
|
|
284
|
-
},
|
|
285
283
|
|
|
286
|
-
disconnectLLM: function (
|
|
284
|
+
disconnectLLM: function (
|
|
285
|
+
options,
|
|
286
|
+
sessionId = 'llm-default-session',
|
|
287
|
+
ownerMeetingId = 'meeting-1'
|
|
288
|
+
) {
|
|
289
|
+
if (!ownerMeetingId) {
|
|
290
|
+
return Promise.reject(new Error('ownerMeetingId is required'));
|
|
291
|
+
}
|
|
292
|
+
|
|
287
293
|
return this.disconnect(options, sessionId).then(() => {
|
|
288
294
|
this.connections.delete(sessionId);
|
|
289
|
-
this.datachannelTokens[sessionId] = undefined;
|
|
290
295
|
});
|
|
291
296
|
},
|
|
292
297
|
};
|
|
293
298
|
});
|
|
294
299
|
|
|
295
|
-
it('calls disconnect and clears session connection
|
|
296
|
-
await instance.disconnectLLM({ code: 3000, reason: 'bye' });
|
|
300
|
+
it('calls disconnect and clears session connection (including token stored in session)', async () => {
|
|
301
|
+
await instance.disconnectLLM({ code: 3000, reason: 'bye' }, 'llm-default-session', 'meeting-1');
|
|
297
302
|
|
|
298
303
|
expect(instance.disconnect).toHaveBeenCalledWith(
|
|
299
304
|
{ code: 3000, reason: 'bye' },
|
|
@@ -301,26 +306,102 @@ describe('plugin-llm', () => {
|
|
|
301
306
|
);
|
|
302
307
|
|
|
303
308
|
expect(instance.connections.has('llm-default-session')).toBe(false);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('disconnectLLM supports legacy call with options only', async () => {
|
|
312
|
+
llmService.disconnect = sinon.stub().resolves(true);
|
|
313
|
+
|
|
314
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 'llm-default-session');
|
|
315
|
+
|
|
316
|
+
const options = {code: 1000, reason: 'legacy'};
|
|
317
|
+
const disconnected = await llmService.disconnectLLM(options);
|
|
318
|
+
|
|
319
|
+
assert.equal(disconnected, true);
|
|
320
|
+
sinon.assert.calledOnceWithExactly(llmService.disconnect, options, 'llm-default-session');
|
|
321
|
+
assert.equal(llmService.getAllConnections().has('llm-default-session'), false);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it('disconnectLLM supports legacy call with options and sessionId', async () => {
|
|
325
|
+
llmService.disconnect = sinon.stub().resolves(true);
|
|
326
|
+
|
|
327
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
328
|
+
|
|
329
|
+
const options = {code: 1000, reason: 'legacy'};
|
|
330
|
+
const disconnected = await llmService.disconnectLLM(options, 's1');
|
|
304
331
|
|
|
305
|
-
|
|
332
|
+
assert.equal(disconnected, true);
|
|
333
|
+
sinon.assert.calledOnceWithExactly(llmService.disconnect, options, 's1');
|
|
334
|
+
assert.equal(llmService.getAllConnections().has('s1'), false);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('disconnectLLM treats null sessionId as default session', async () => {
|
|
338
|
+
llmService.disconnect = sinon.stub().resolves(true);
|
|
339
|
+
|
|
340
|
+
await llmService.registerAndConnect(
|
|
341
|
+
locusUrl,
|
|
342
|
+
datachannelUrl,
|
|
343
|
+
undefined,
|
|
344
|
+
'llm-default-session'
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
const options = {code: 1000, reason: 'legacy-null-session'};
|
|
348
|
+
const disconnected = await llmService.disconnectLLM(options, null);
|
|
349
|
+
|
|
350
|
+
assert.equal(disconnected, true);
|
|
351
|
+
sinon.assert.calledOnceWithExactly(llmService.disconnect, options, 'llm-default-session');
|
|
352
|
+
assert.equal(llmService.getAllConnections().has('llm-default-session'), false);
|
|
306
353
|
});
|
|
307
354
|
|
|
308
355
|
it('propagates disconnect errors', async () => {
|
|
309
356
|
instance.disconnect.mockRejectedValue(new Error('disconnect failed'));
|
|
310
357
|
|
|
311
358
|
await expect(
|
|
312
|
-
instance.disconnectLLM({ code: 3000, reason: 'bye' })
|
|
359
|
+
instance.disconnectLLM({ code: 3000, reason: 'bye' }, 'llm-default-session', 'meeting-1')
|
|
313
360
|
).rejects.toThrow('disconnect failed');
|
|
314
361
|
});
|
|
315
362
|
});
|
|
316
363
|
|
|
317
364
|
describe('#setRefreshHandler', () => {
|
|
365
|
+
beforeEach(() => {
|
|
366
|
+
llmService.setRefreshHandler = LLMChannel.prototype.setRefreshHandler.bind(llmService);
|
|
367
|
+
llmService.refreshDataChannelToken = LLMChannel.prototype.refreshDataChannelToken.bind(llmService);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it('defaults to llm-default-session when sessionId is omitted', () => {
|
|
371
|
+
const handler = sinon.stub().resolves({ body: { datachannelToken: 'legacyToken' } });
|
|
372
|
+
|
|
373
|
+
llmService.setRefreshHandler(handler);
|
|
374
|
+
|
|
375
|
+
return llmService.refreshDataChannelToken().then((result) => {
|
|
376
|
+
assert.equal(result.body.datachannelToken, 'legacyToken');
|
|
377
|
+
sinon.assert.calledOnce(handler);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
318
381
|
it('stores the provided handler', () => {
|
|
319
382
|
const handler = sinon.stub().resolves({ body: { datachannelToken: 'newToken' } });
|
|
320
|
-
llmService.setRefreshHandler(handler);
|
|
383
|
+
llmService.setRefreshHandler(handler, 'llm-default-session');
|
|
384
|
+
|
|
385
|
+
return llmService.refreshDataChannelToken().then((result) => {
|
|
386
|
+
assert.equal(result.body.datachannelToken, 'newToken');
|
|
387
|
+
sinon.assert.calledOnce(handler);
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it('stores handlers per session id', () => {
|
|
392
|
+
const handlerS1 = sinon.stub().resolves({ body: { datachannelToken: 'token-s1' } });
|
|
393
|
+
const handlerS2 = sinon.stub().resolves({ body: { datachannelToken: 'token-s2' } });
|
|
394
|
+
|
|
395
|
+
llmService.setRefreshHandler(handlerS1, 's1');
|
|
396
|
+
llmService.setRefreshHandler(handlerS2, 's2');
|
|
321
397
|
|
|
322
|
-
|
|
323
|
-
|
|
398
|
+
return Promise.all([
|
|
399
|
+
llmService.refreshDataChannelToken('s1'),
|
|
400
|
+
llmService.refreshDataChannelToken('s2'),
|
|
401
|
+
]).then(([resultS1, resultS2]) => {
|
|
402
|
+
assert.equal(resultS1.body.datachannelToken, 'token-s1');
|
|
403
|
+
assert.equal(resultS2.body.datachannelToken, 'token-s2');
|
|
404
|
+
});
|
|
324
405
|
});
|
|
325
406
|
});
|
|
326
407
|
|
|
@@ -341,6 +422,11 @@ describe('plugin-llm', () => {
|
|
|
341
422
|
});
|
|
342
423
|
|
|
343
424
|
describe('#refreshDataChannelToken', () => {
|
|
425
|
+
beforeEach(() => {
|
|
426
|
+
llmService.setRefreshHandler = LLMChannel.prototype.setRefreshHandler.bind(llmService);
|
|
427
|
+
llmService.refreshDataChannelToken = LLMChannel.prototype.refreshDataChannelToken.bind(llmService);
|
|
428
|
+
});
|
|
429
|
+
|
|
344
430
|
it('returns null and logs warn if no handler is set', async () => {
|
|
345
431
|
const warnSpy = llmService.logger.warn
|
|
346
432
|
|
|
@@ -351,7 +437,7 @@ describe('plugin-llm', () => {
|
|
|
351
437
|
sinon.assert.calledOnce(warnSpy);
|
|
352
438
|
sinon.assert.calledWithMatch(
|
|
353
439
|
warnSpy,
|
|
354
|
-
sinon.match('LLM refreshHandler is not set')
|
|
440
|
+
sinon.match('LLM refreshHandler is not set for session')
|
|
355
441
|
);
|
|
356
442
|
});
|
|
357
443
|
|
|
@@ -359,7 +445,7 @@ describe('plugin-llm', () => {
|
|
|
359
445
|
const mockToken = { body: { datachannelToken: 'newToken', isPracticeSession: false } };
|
|
360
446
|
const handler = sinon.stub().resolves(mockToken);
|
|
361
447
|
|
|
362
|
-
llmService.setRefreshHandler(handler);
|
|
448
|
+
llmService.setRefreshHandler(handler, 'llm-default-session');
|
|
363
449
|
|
|
364
450
|
const token = await llmService.refreshDataChannelToken();
|
|
365
451
|
|
|
@@ -367,9 +453,21 @@ describe('plugin-llm', () => {
|
|
|
367
453
|
sinon.assert.calledOnce(handler);
|
|
368
454
|
});
|
|
369
455
|
|
|
456
|
+
it('uses the handler for the provided session id', async () => {
|
|
457
|
+
const mockToken = { body: { datachannelToken: 'session-token', isPracticeSession: true } };
|
|
458
|
+
const handler = sinon.stub().resolves(mockToken);
|
|
459
|
+
|
|
460
|
+
llmService.setRefreshHandler(handler, 's2');
|
|
461
|
+
|
|
462
|
+
const token = await llmService.refreshDataChannelToken('s2');
|
|
463
|
+
|
|
464
|
+
assert.equal(token, mockToken);
|
|
465
|
+
sinon.assert.calledOnce(handler);
|
|
466
|
+
});
|
|
467
|
+
|
|
370
468
|
it('logs warn and returns null when handler rejects', async () => {
|
|
371
469
|
const handler = sinon.stub().rejects(new Error('throw error'));
|
|
372
|
-
llmService.setRefreshHandler(handler);
|
|
470
|
+
llmService.setRefreshHandler(handler, 'llm-default-session');
|
|
373
471
|
|
|
374
472
|
const warnSpy = llmService.logger.warn
|
|
375
473
|
|
|
@@ -392,6 +490,13 @@ describe('plugin-llm', () => {
|
|
|
392
490
|
llmService.setDatachannelToken('123abc','llm-practice-session');
|
|
393
491
|
assert.equal(llmService.getDatachannelToken('llm-practice-session'), '123abc');
|
|
394
492
|
});
|
|
493
|
+
|
|
494
|
+
it('supports arbitrary session id token keys', () => {
|
|
495
|
+
llmService.setDatachannelToken('token-s1', 'session-custom-1');
|
|
496
|
+
|
|
497
|
+
assert.equal(llmService.getDatachannelToken('session-custom-1'), 'token-s1');
|
|
498
|
+
});
|
|
499
|
+
|
|
395
500
|
});
|
|
396
501
|
|
|
397
502
|
describe('#setOwnerMeetingId / #getOwnerMeetingId', () => {
|
|
@@ -443,7 +548,11 @@ describe('plugin-llm', () => {
|
|
|
443
548
|
llmService.setOwnerMeetingId('meeting-1');
|
|
444
549
|
assert.equal(llmService.getOwnerMeetingId(), 'meeting-1');
|
|
445
550
|
|
|
446
|
-
await llmService.disconnectLLM(
|
|
551
|
+
await llmService.disconnectLLM(
|
|
552
|
+
{code: 3050, reason: 'done (permanent)'},
|
|
553
|
+
'llm-default-session',
|
|
554
|
+
'meeting-1'
|
|
555
|
+
);
|
|
447
556
|
|
|
448
557
|
// Session entry was deleted, so ownerMeetingId is gone.
|
|
449
558
|
assert.equal(llmService.getOwnerMeetingId(), undefined);
|
|
@@ -477,20 +586,33 @@ describe('plugin-llm', () => {
|
|
|
477
586
|
await llmService.registerAndConnect(locusUrl2, datachannelUrl2, undefined, 's2');
|
|
478
587
|
|
|
479
588
|
const options = {code: 1000, reason: 'test'};
|
|
480
|
-
await llmService.disconnectLLM(options, 's1');
|
|
589
|
+
const disconnected = await llmService.disconnectLLM(options, 's1', 'meeting-1');
|
|
481
590
|
|
|
591
|
+
assert.equal(disconnected, true);
|
|
482
592
|
sinon.assert.calledOnceWithExactly(llmService.disconnect, options, 's1');
|
|
483
593
|
|
|
484
594
|
const all = llmService.getAllConnections();
|
|
485
595
|
assert.equal(all.has('s1'), false);
|
|
486
596
|
assert.equal(all.has('s2'), true);
|
|
597
|
+
assert.equal(llmService.getDatachannelToken('s1'), undefined);
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
it('disconnectLLM skips disconnect when ownerMeetingId does not match', async () => {
|
|
601
|
+
llmService.disconnect = sinon.stub().resolves(true);
|
|
602
|
+
|
|
603
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
604
|
+
llmService.setOwnerMeetingId('meeting-1', 's1');
|
|
605
|
+
|
|
606
|
+
const options = {code: 1000, reason: 'test'};
|
|
607
|
+
const disconnected = await llmService.disconnectLLM(options, 's1', 'meeting-2');
|
|
487
608
|
|
|
488
|
-
assert.equal(
|
|
609
|
+
assert.equal(disconnected, false);
|
|
610
|
+
sinon.assert.notCalled(llmService.disconnect);
|
|
611
|
+
assert.equal(llmService.getAllConnections().has('s1'), true);
|
|
489
612
|
});
|
|
490
613
|
|
|
491
614
|
it('disconnectAllLLM clears all sessions', async () => {
|
|
492
615
|
llmService.disconnectAll = sinon.stub().resolves(true);
|
|
493
|
-
sinon.spy(llmService, 'resetDatachannelTokens');
|
|
494
616
|
|
|
495
617
|
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
496
618
|
await llmService.registerAndConnect(locusUrl2, datachannelUrl2, undefined, 's2');
|
|
@@ -502,5 +624,90 @@ describe('plugin-llm', () => {
|
|
|
502
624
|
});
|
|
503
625
|
});
|
|
504
626
|
|
|
627
|
+
describe('#getLocusUrlByDatachannelUrl', () => {
|
|
628
|
+
const locusUrl2 = 'https://locus-b.wbx2.com/locus/api/v1/loci/456';
|
|
629
|
+
const datachannelUrl2 = 'https://board-b.wbx2.com/datachannel/api/v1/locus/ps-encoded/registrations';
|
|
630
|
+
|
|
631
|
+
// Ampersand State.extend() does not always propagate prototype methods
|
|
632
|
+
// added to child classes, so we bind the method from the class prototype
|
|
633
|
+
// directly onto the test instance.
|
|
634
|
+
beforeEach(() => {
|
|
635
|
+
llmService.getLocusUrlByDatachannelUrl = LLMChannel.prototype.getLocusUrlByDatachannelUrl.bind(llmService);
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
it('returns locusUrl when request URL matches a session datachannelUrl', async () => {
|
|
639
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
640
|
+
await llmService.registerAndConnect(locusUrl2, datachannelUrl2, undefined, 's2');
|
|
641
|
+
|
|
642
|
+
const result = llmService.getLocusUrlByDatachannelUrl(datachannelUrl2 + '/some-path');
|
|
643
|
+
|
|
644
|
+
assert.equal(result, locusUrl2);
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
it('returns undefined when no session matches the request URL', async () => {
|
|
648
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
649
|
+
|
|
650
|
+
const result = llmService.getLocusUrlByDatachannelUrl('https://unknown.example.com/path');
|
|
651
|
+
|
|
652
|
+
assert.equal(result, undefined);
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
it('matches locusUrl when request host is rewritten but pathname matches', async () => {
|
|
656
|
+
await llmService.registerAndConnect(locusUrl2, datachannelUrl2, undefined, 's2');
|
|
657
|
+
|
|
658
|
+
const rewrittenHostRequestUrl =
|
|
659
|
+
'https://hostmap-rewritten.example.com/datachannel/api/v1/locus/ps-encoded/registrations/events';
|
|
660
|
+
const result = llmService.getLocusUrlByDatachannelUrl(rewrittenHostRequestUrl);
|
|
661
|
+
|
|
662
|
+
assert.equal(result, locusUrl2);
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
it('returns undefined when no connections exist', () => {
|
|
666
|
+
const result = llmService.getLocusUrlByDatachannelUrl(datachannelUrl);
|
|
667
|
+
|
|
668
|
+
assert.equal(result, undefined);
|
|
669
|
+
});
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
describe('#getSessionIdByDatachannelUrl', () => {
|
|
673
|
+
const datachannelUrl2 = 'https://board-b.wbx2.com/datachannel/api/v1/locus/ps-encoded/registrations';
|
|
674
|
+
|
|
675
|
+
beforeEach(() => {
|
|
676
|
+
llmService.getSessionIdByDatachannelUrl = LLMChannel.prototype.getSessionIdByDatachannelUrl.bind(llmService);
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
it('returns sessionId when request URL matches a session datachannelUrl', async () => {
|
|
680
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
681
|
+
await llmService.registerAndConnect('https://locus-b.wbx2.com/locus/api/v1/loci/456', datachannelUrl2, undefined, 's2');
|
|
682
|
+
|
|
683
|
+
const result = llmService.getSessionIdByDatachannelUrl(datachannelUrl2 + '/some-path');
|
|
684
|
+
|
|
685
|
+
assert.equal(result, 's2');
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
it('returns undefined when no session matches the request URL', async () => {
|
|
689
|
+
await llmService.registerAndConnect(locusUrl, datachannelUrl, undefined, 's1');
|
|
690
|
+
|
|
691
|
+
const result = llmService.getSessionIdByDatachannelUrl('https://unknown.example.com/path');
|
|
692
|
+
|
|
693
|
+
assert.equal(result, undefined);
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it('matches sessionId when request host is rewritten but pathname matches', async () => {
|
|
697
|
+
await llmService.registerAndConnect(
|
|
698
|
+
'https://locus-b.wbx2.com/locus/api/v1/loci/456',
|
|
699
|
+
datachannelUrl2,
|
|
700
|
+
undefined,
|
|
701
|
+
's2'
|
|
702
|
+
);
|
|
703
|
+
|
|
704
|
+
const rewrittenHostRequestUrl =
|
|
705
|
+
'https://hostmap-rewritten.example.com/datachannel/api/v1/locus/ps-encoded/registrations/messages';
|
|
706
|
+
const result = llmService.getSessionIdByDatachannelUrl(rewrittenHostRequestUrl);
|
|
707
|
+
|
|
708
|
+
assert.equal(result, 's2');
|
|
709
|
+
});
|
|
710
|
+
});
|
|
711
|
+
|
|
505
712
|
});
|
|
506
713
|
});
|