Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/rich-actors-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'livekit-client': patch
---

Add new areTokenSourceFetchOptionsEqual function
36 changes: 35 additions & 1 deletion src/room/token-source/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TokenSourceResponse } from '@livekit/protocol';
import { describe, expect, it } from 'vitest';
import { decodeTokenPayload, isResponseTokenValid } from './utils';
import { areTokenSourceFetchOptionsEqual, decodeTokenPayload, isResponseTokenValid } from './utils';

// Test JWTs created for test purposes only.
// None of these actually auth against anything.
Expand Down Expand Up @@ -61,3 +61,37 @@ describe('decodeTokenPayload', () => {
expect(payload.roomConfig?.agents![0].metadata).toBe('test agent metadata');
});
});

describe('areTokenSourceFetchOptionsEqual', () => {
it('should ensure two identical options objects of different references are equal', () => {
expect(
areTokenSourceFetchOptionsEqual(
{ agentName: 'my agent name' },
{ agentName: 'my agent name' },
),
).to.equal(true);
});
it('should ensure two empty options objects are equal', () => {
expect(areTokenSourceFetchOptionsEqual({}, {})).to.equal(true);
});
it('should ensure empty on the left and filled on the right are not equal', () => {
expect(areTokenSourceFetchOptionsEqual({}, { agentName: 'my agent name' })).to.equal(false);
});
it('should ensure filled on the left and empty on the right are not equal', () => {
expect(areTokenSourceFetchOptionsEqual({ agentName: 'my agent name' }, {})).to.equal(false);
});
it('should ensure objects with different keys/values are not equal', () => {
expect(
areTokenSourceFetchOptionsEqual(
{ agentName: 'foo' },
{ agentName: 'bar', agentMetadata: 'baz' },
),
).to.equal(false);
expect(
areTokenSourceFetchOptionsEqual(
{ agentName: 'bar', agentMetadata: 'baz' },
{ agentName: 'foo' },
),
).to.equal(false);
});
});
34 changes: 33 additions & 1 deletion src/room/token-source/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { RoomConfiguration, type TokenSourceResponse } from '@livekit/protocol';
import { decodeJwt } from 'jose';
import type { RoomConfigurationObject, TokenPayload } from './types';
import type { RoomConfigurationObject, TokenPayload, TokenSourceFetchOptions } from './types';

const ONE_SECOND_IN_MILLISECONDS = 1000;
const ONE_MINUTE_IN_MILLISECONDS = 60 * ONE_SECOND_IN_MILLISECONDS;
Expand Down Expand Up @@ -39,3 +39,35 @@ export function decodeTokenPayload(token: string) {

return mappedPayload;
}

/** Given two TokenSourceFetchOptions values, check to see if they are deep equal. */
export function areTokenSourceFetchOptionsEqual(
a: TokenSourceFetchOptions,
b: TokenSourceFetchOptions,
) {
const allKeysSet = new Set([...Object.keys(a), ...Object.keys(b)]) as Set<
keyof TokenSourceFetchOptions
>;

for (const key of allKeysSet) {
switch (key) {
case 'roomName':
case 'participantName':
case 'participantIdentity':
case 'participantMetadata':
case 'participantAttributes':
case 'agentName':
case 'agentMetadata':
if (a[key] !== b[key]) {
return false;
}
break;
default:
// ref: https://stackoverflow.com/a/58009992
const exhaustiveCheckedKey: never = key;
throw new Error(`Options key ${exhaustiveCheckedKey} not being checked for equality!`);
}
}

return true;
}
Loading