Skip to content

Commit

Permalink
Merge pull request #1204 from dm3-org/add-conversation-test
Browse files Browse the repository at this point in the history
Add basic Messages and Conversation API
  • Loading branch information
AlexNi245 authored Nov 22, 2024
2 parents 39158e2 + 0620b51 commit 648894a
Show file tree
Hide file tree
Showing 19 changed files with 763 additions and 136 deletions.
1 change: 1 addition & 0 deletions packages/js-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@babel/preset-env": "^7.19.4",
"@babel/preset-typescript": "^7.18.6",
"@types/supertest": "^2.0.12",
"axios-mock-adapter": "^2.1.0",
"babel-cli": "^6.26.0",
"babel-jest": "^29.2.2",
"babel-preset-env": "^1.7.0",
Expand Down
6 changes: 3 additions & 3 deletions packages/js-sdk/src/Dm3.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Conversations } from './conversation/Conversations';
import { Tld } from './tld/Tld';
import { ITLDResolver } from './tld/nameService/ITLDResolver';

export class Dm3 {
public readonly conversations: Conversations;
public readonly tld: Tld;
public readonly tld: ITLDResolver;

constructor(conversations: Conversations, tld: Tld) {
constructor(conversations: Conversations, tld: ITLDResolver) {
this.conversations = conversations;
this.tld = tld;
}
Expand Down
249 changes: 226 additions & 23 deletions packages/js-sdk/src/Dm3Sdk.test.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,237 @@
import { StorageAPI } from '@dm3-org/dm3-lib-storage';
import {
getMockDeliveryServiceProfile,
MockDeliveryServiceProfile,
MockedUserProfile,
MockMessageFactory,
mockUserProfile,
} from '@dm3-org/dm3-lib-test-helper';
import axios from 'axios';
import { ethers } from 'ethers';
import { Dm3Sdk, Dm3SdkConfig } from './Dm3Sdk';
import { StorageAPI } from '@dm3-org/dm3-lib-storage';

import MockAdapter from 'axios-mock-adapter';
import { normalizeEnsName } from '@dm3-org/dm3-lib-profile';
import { ITLDResolver } from './tld/nameService/ITLDResolver';

describe('Dm3Sdk', () => {
let upController: ethers.Signer;
let alice: MockedUserProfile;
let bob: MockedUserProfile;
let karl: MockedUserProfile;

//Axios mock to mock the http requests
let axiosMock;

let deliveryService: MockDeliveryServiceProfile;

beforeEach(async () => {
upController = ethers.Wallet.createRandom();
alice = await mockUserProfile(
ethers.Wallet.createRandom(),
'alice.up',
['test.io'],
);
bob = await mockUserProfile(ethers.Wallet.createRandom(), 'bob.up', [
'test.io',
]);

karl = await mockUserProfile(ethers.Wallet.createRandom(), 'karl.up', [
'test.io',
]);

deliveryService = await getMockDeliveryServiceProfile(
ethers.Wallet.createRandom(),
'http://localhost:3000',
);
axiosMock = new MockAdapter(axios);

//Mock BackendConnector HttpRequests
//Mock profileExistsOnDeliveryService
axiosMock
.onGet(
`http://localhost:4060/profile/${normalizeEnsName(
alice.address,
)}.addr.test`,
)
.reply(200);
//Mock getChallenge
axiosMock
.onGet(
`http://localhost:4060/auth/${normalizeEnsName(
alice.address,
)}.addr.test`,
)
.reply(200, 'mock-challenge');

//Mock getToken
axiosMock
.onPost(
`http://localhost:4060/auth/${normalizeEnsName(
alice.address,
)}.addr.test`,
)
.reply(200);
});

it('test', async () => {
const luksoProvider = () => ({
send: () => Promise.resolve([]),
getSigner: () => Promise.resolve(upController),
describe('conversations', () => {
it('can add a conversation to the contact list', async () => {
const mockTldResolver = {
resolveTLDtoAlias: async () =>
`${normalizeEnsName(bob.address)}.addr.test`,
resolveAliasToTLD: async () => 'bob.eth',
} as unknown as ITLDResolver;

const mockConfig: Dm3SdkConfig = {
mainnetProvider: {} as ethers.providers.JsonRpcProvider,
storageApi: {
addConversation: async () => {},
} as unknown as StorageAPI,
nonce: '1',
defaultDeliveryService: 'test.io',
addressEnsSubdomain: '.addr.test',
userEnsSubdomain: '.user.test',
resolverBackendUrl: 'resolver.io',
backendUrl: 'http://localhost:4060',
_tld: mockTldResolver,
};

const dm3 = await new Dm3Sdk(mockConfig).login({
profileKeys: alice.profileKeys,
profile: alice.signedUserProfile,
accountAddress: alice.address,
});

await dm3.conversations.addConversation('bob.eth');
expect(dm3.conversations.list.length).toBe(1);
expect(dm3.conversations.list[0].contact.name).toBe('bob.eth');
});
it('can multiple conversations to the contact list', async () => {
const mockTldResolver = {
resolveTLDtoAlias: async (ensName: string) => {
if (ensName === 'alice.eth') {
return `${normalizeEnsName(alice.address)}.addr.test`;
}
if (ensName === 'bob.eth') {
return `${normalizeEnsName(bob.address)}.addr.test`;
}
return `${normalizeEnsName(karl.address)}.addr.test`;
},
resolveAliasToTLD: async (ensName: string) => {
if (
normalizeEnsName(ensName) ===
normalizeEnsName(alice.address) + '.addr.test'
) {
return 'alice.eth';
}
if (
normalizeEnsName(ensName) ===
normalizeEnsName(bob.address) + '.addr.test'
) {
return 'bob.eth';
}
return 'karl.eth';
},
} as unknown as ITLDResolver;

const mockConfig: Dm3SdkConfig = {
mainnetProvider: {} as ethers.providers.JsonRpcProvider,
storageApi: {
addConversation: async () => {},
} as unknown as StorageAPI,
nonce: '1',
defaultDeliveryService: 'test.io',
addressEnsSubdomain: '.addr.test',
userEnsSubdomain: '.user.test',
resolverBackendUrl: 'resolver.io',
backendUrl: 'http://localhost:4060',
_tld: mockTldResolver,
};

const dm3 = await new Dm3Sdk(mockConfig).login({
profileKeys: alice.profileKeys,
profile: alice.signedUserProfile,
accountAddress: alice.address,
});

await dm3.conversations.addConversation('bob.eth');
await dm3.conversations.addConversation('karl.eth');

expect(dm3.conversations.list.length).toBe(2);
expect(dm3.conversations.list[0].contact.name).toBe('bob.eth');
expect(dm3.conversations.list[1].contact.name).toBe('karl.eth');
});
it('dont add duplicate conversations', async () => {
const mockTldResolver = {
resolveTLDtoAlias: async () =>
`${normalizeEnsName(bob.address)}.addr.test`,
resolveAliasToTLD: async () => 'bob.eth',
} as unknown as ITLDResolver;

const mockConfig: Dm3SdkConfig = {
mainnetProvider: {} as ethers.providers.JsonRpcProvider,
storageApi: {
addConversation: async () => {},
} as unknown as StorageAPI,
nonce: '1',
defaultDeliveryService: 'test.io',
addressEnsSubdomain: '.addr.test',
userEnsSubdomain: '.user.test',
resolverBackendUrl: 'resolver.io',
backendUrl: 'http://localhost:4060',
_tld: mockTldResolver,
};

const dm3 = await new Dm3Sdk(mockConfig).login({
profileKeys: alice.profileKeys,
profile: alice.signedUserProfile,
accountAddress: alice.address,
});

await dm3.conversations.addConversation('bob.eth');
await dm3.conversations.addConversation('bob.eth');
expect(dm3.conversations.list.length).toBe(1);
expect(dm3.conversations.list[0].contact.name).toBe('bob.eth');
});
});

describe('Messages', () => {
it('can send a message', async () => {
const mockTldResolver = {
resolveTLDtoAlias: async () =>
`${normalizeEnsName(bob.address)}.addr.test`,
resolveAliasToTLD: async () => 'bob.eth',
} as unknown as ITLDResolver;

const mockConfig: Dm3SdkConfig = {
mainnetProvider: {} as ethers.providers.JsonRpcProvider,
storageApi: {
addConversation: async () => {},
addMessage: async () => {},
} as unknown as StorageAPI,
nonce: '1',
defaultDeliveryService: 'test.io',
addressEnsSubdomain: '.addr.test',
userEnsSubdomain: '.user.test',
resolverBackendUrl: 'resolver.io',
backendUrl: 'http://localhost:4060',
_tld: mockTldResolver,
};

const dm3 = await new Dm3Sdk(mockConfig).login({
profileKeys: alice.profileKeys,
profile: alice.signedUserProfile,
accountAddress: alice.address,
});

expect(
(await dm3.conversations.addConversation('bob.eth'))?.messages
.list.length,
).toBe(0);

const c = await dm3.conversations.addConversation('bob.eth');

await c?.messages.sendMessage('Hi');
expect(c?.messages.list.length).toBe(1);
expect(c?.messages.list[0].envelop.message.message).toBe('Hi');
});
const mockConfig: Dm3SdkConfig = {
mainnetProvider: {} as ethers.providers.JsonRpcProvider,
lukso: luksoProvider as any,
nonce: '1',
defaultDeliveryService: 'test.io',
addressEnsSubdomain: 'addr.test',
userEnsSubdomain: 'user.test',
resolverBackendUrl: 'resolver.io',
backendUrl: 'backend.io',
storageApi: {} as StorageAPI,
};

// const dm3 = await new Dm3Sdk().universalProfileLogin();
// await dm3.conversations.addConversation('karl.eth');
// const c = dm3.conversations.list;
// const karl = c[0];
});
});
68 changes: 46 additions & 22 deletions packages/js-sdk/src/Dm3Sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { StorageAPI } from '@dm3-org/dm3-lib-storage';
import { ethers } from 'ethers';
import { Tld } from './tld/Tld';
import { Dm3 } from './Dm3';
import { ITLDResolver } from './tld/nameService/ITLDResolver';

/**
* DM3SDK
Expand All @@ -36,7 +37,7 @@ export interface Dm3SdkConfig {
userEnsSubdomain: string;
resolverBackendUrl: string;
backendUrl: string;
lukso?: ethers.providers.ExternalProvider;
_tld?: ITLDResolver;
}

export class Dm3Sdk {
Expand Down Expand Up @@ -69,6 +70,11 @@ export class Dm3Sdk {
*/
public conversations: Conversations;

/**
* DM3 TLD
*/
private _tld?: ITLDResolver;

constructor(config: Dm3SdkConfig) {
//TODO keep ethers v5 for know but extract into common interface later
this.mainnetProvider = config.mainnetProvider;
Expand All @@ -78,29 +84,30 @@ export class Dm3Sdk {
this.addressEnsSubdomain = config.addressEnsSubdomain;
this.userEnsSubdomain = config.userEnsSubdomain;
this.resolverBackendUrl = config.resolverBackendUrl;
//this.backendUrl = config.backendUrl;
this.lukso = config.lukso;
this.backendUrl = config.backendUrl;
this.storageApi = config.storageApi;
this._tld = config._tld;
}

public async universalProfileLogin() {
if (!this.lukso) {
throw new Error('Lukso provider not found');
}
const tld = new Tld(
this.mainnetProvider,
this.addressEnsSubdomain,
this.userEnsSubdomain,
this.resolverBackendUrl,
);
const lc = await LuksoConnector._instance(
this.lukso,
this.nonce,
this.defaultDeliveryService,
);
const loginResult = await lc.login();

const { profileKeys, profile, accountAddress } = loginResult as Success;
/**
* login can be used to login with a profile regardles the connector. Its also great for testing
*/
public async login({
profileKeys,
profile,
accountAddress,
}: {
profileKeys: ProfileKeys;
profile: SignedUserProfile;
accountAddress: string;
}) {
const tld =
this._tld ??
new Tld(
this.mainnetProvider,
this.addressEnsSubdomain,
this.userEnsSubdomain,
this.resolverBackendUrl,
);

this.profileKeys = profileKeys;
this.profile = profile;
Expand Down Expand Up @@ -130,6 +137,7 @@ export class Dm3Sdk {
tld,
this.mainnetProvider,
account,
profileKeys,
this.addressEnsSubdomain,
);

Expand All @@ -142,6 +150,22 @@ export class Dm3Sdk {
return new Dm3(conversations, tld);
}

//TODO use type of injected lukso provider
public async universalProfileLogin(lukso: any) {
if (!lukso) {
throw new Error('Lukso provider not found');
}
const lc = await LuksoConnector._instance(
lukso,
this.nonce,
this.defaultDeliveryService,
);
const loginResult = await lc.login();

const { profileKeys, profile, accountAddress } = loginResult as Success;
return await this.login({ profileKeys, profile, accountAddress });
}

private async initializeBackendConnector(
accountAddress: string,
profileKeys: ProfileKeys,
Expand Down
Loading

0 comments on commit 648894a

Please sign in to comment.