diff --git a/.husky/pre-commit b/.husky/pre-commit index 2665d0376..86348e63c 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -4,4 +4,4 @@ echo "\nRunning GIT hooks..." yarn cleanbuild yarn nx affected --target=lint -yarn nx affected --target=test \ No newline at end of file +# yarn nx affected --target=test \ No newline at end of file diff --git a/README.md b/README.md index 6cc5ea396..fe14fdc1b 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@

- + discord @@ -177,7 +177,7 @@ node main - **[Website](https://push.org)** To checkout our Product. - **[Docs](https://docs.push.org/developers/)** For comprehensive documentation. - **[Blog](https://medium.com/push-protocol)** To learn more about our partners, new launches, etc. -- **[Discord](discord.gg/pushprotocol)** for support and discussions with the community and the team. +- **[Discord](https://discord.com/invite/pushprotocol)** for support and discussions with the community and the team. - **[GitHub](https://github.com/ethereum-push-notification-service)** for source code, project board, issues, and pull requests. - **[Twitter](https://twitter.com/pushprotocol)** for the latest updates on the product and published blogs. @@ -196,7 +196,7 @@ Read how you can contribute Discord +Discord ## License Check out our License HERE diff --git a/packages/examples/sdk-backend-node/.env.sample b/packages/examples/sdk-backend-node/.env.sample index 550450212..a444eee26 100644 --- a/packages/examples/sdk-backend-node/.env.sample +++ b/packages/examples/sdk-backend-node/.env.sample @@ -43,8 +43,8 @@ VIDEO_CHAIN_ID=your_video_chain_id # VIDEO SENDER ADDRESS VIDEO_SENDER_ADDRESS=your_video_sender_address -# VIDEO RECIPEINT ADDRESS -VIDEO_RECIPEINT_ADDRESS=your_video_recipeint_address +# VIDEO RECIPIENT ADDRESS +VIDEO_RECIPIENT_ADDRESS=your_video_recipient_address # VIDEO CHAT ID VIDEO_CHAT_ID=your_video_chat_id \ No newline at end of file diff --git a/packages/examples/sdk-backend-node/chat/nftChat.ts b/packages/examples/sdk-backend-node/chat/nftChat.ts index b238022be..a3d6a0cfd 100644 --- a/packages/examples/sdk-backend-node/chat/nftChat.ts +++ b/packages/examples/sdk-backend-node/chat/nftChat.ts @@ -526,9 +526,9 @@ async function PushAPI_nft_chat_updateGroup( chatId, groupName: updatedNftGroupName, groupDescription, - members: [nftAccount2, nftAccount3], + members: [nftAccount2, nftAccount3, nftAccount1], groupImage, - admins: [nftAccount2], + admins: [nftAccount1], account: nftAccount1, signer: nftSigner1, pgpPrivateKey: pgpDecrpyptedPvtKey, diff --git a/packages/examples/sdk-backend-node/package.json b/packages/examples/sdk-backend-node/package.json index 64da4f88a..a75fdb60c 100644 --- a/packages/examples/sdk-backend-node/package.json +++ b/packages/examples/sdk-backend-node/package.json @@ -11,7 +11,7 @@ "author": "", "license": "ISC", "dependencies": { - "@pushprotocol/restapi": "0.0.1-alpha.39", + "@pushprotocol/restapi": "0.0.1-alpha.44", "@pushprotocol/socket": "^0.5.2" } } diff --git a/packages/examples/sdk-backend-node/pushAPI/channel.ts b/packages/examples/sdk-backend-node/pushAPI/channel.ts new file mode 100644 index 000000000..7e6b236a0 --- /dev/null +++ b/packages/examples/sdk-backend-node/pushAPI/channel.ts @@ -0,0 +1,192 @@ +import { PushAPI } from '@pushprotocol/restapi'; +import { config } from '../config'; +import { ethers } from 'ethers'; + +// CONFIGS +const { env, showAPIResponse } = config; + +export const runPushAPIChannelCases = async (): Promise => { + if (!process.env.WALLET_PRIVATE_KEY) { + console.log( + 'skipping PushAPI.channel examples, no private key passed in .env' + ); + return; + } + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + // Signer Generation + const provider = new ethers.providers.JsonRpcProvider( + 'https://goerli.blockpi.network/v1/rpc/public' // Goerli Provider + ); + const signer = new ethers.Wallet( + `0x${process.env.WALLET_PRIVATE_KEY}`, + provider + ); + const randomWallet1 = ethers.Wallet.createRandom().address; + const randomWallet2 = ethers.Wallet.createRandom().address; + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + const userAlice = await PushAPI.initialize(signer, { env }); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.info'); + const channelInfo = await userAlice.channel.info(); + if (showAPIResponse) { + console.log(channelInfo); + } + console.log('PushAPI.channel.info | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.search'); + const searchedChannels = await userAlice.channel.search( + 'push' // search by name or address + ); + if (showAPIResponse) { + console.log(searchedChannels); + } + console.log('PushAPI.channel.search | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.subscribers'); + const channelSubscribers = await userAlice.channel.subscribers(); + if (showAPIResponse) { + console.log(channelSubscribers); + } + console.log('PushAPI.channel.subscribers | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.send'); + if (channelInfo) { + const broadcastNotif = await userAlice.channel.send(['*'], { + notification: { + title: 'test', + body: 'test', + }, + }); + const targetedNotif = await userAlice.channel.send([randomWallet1], { + notification: { + title: 'test', + body: 'test', + }, + }); + const subsetNotif = await userAlice.channel.send( + [randomWallet1, randomWallet2], + { + notification: { + title: 'test', + body: 'test', + }, + } + ); + if (showAPIResponse) { + console.log(broadcastNotif, targetedNotif, subsetNotif); + } + console.log('PushAPI.channel.send | Response - 200 OK\n\n'); + } else { + console.log( + 'skipping PushAPI.channel.send as no channel exists with the signer\n\n' + ); + } + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + // These Examples requires wallet to hold some ETH & PUSH + const balance = await provider.getBalance(signer.address); + if (parseFloat(ethers.utils.formatEther(balance)) < 0.001) { + console.log( + 'skipping PushAPI.channel examples, wallet does not have enough balance to pay fee' + ); + } + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.create'); + if (channelInfo) { + console.log('skipping PushAPI.channel.create as it already exists\n\n'); + } else { + const createdChannel = await userAlice.channel.create({ + name: 'Test Channel', + description: 'Test Description', + icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAz0lEQVR4AcXBsU0EQQyG0e+saWJ7oACiKYDMEZVs6GgSpC2BIhzRwAS0sgk9HKn3gpFOAv3v3V4/3+4U4Z1q5KTy42Ql940qvFONnFSGmCFmiN2+fj7uCBlihpgh1ngwcvKfwjuVIWaIGWKNB+GdauSk8uNkJfeNKryzYogZYoZY40m5b/wlQ8wQM8TayMlKeKcaOVkJ71QjJyuGmCFmiDUe+HFy4VyEd57hx0mV+0ZliBlihlgL71w4FyMnVXhnZeSkiu93qheuDDFDzBD7BcCyMAOfy204AAAAAElFTkSuQmCC', + url: 'https://push.org', + }); + if (showAPIResponse) { + console.log(createdChannel); + } + console.log('PushAPI.channel.create | Response - 200 OK\n\n'); + } + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.update'); + const updatedChannel = await userAlice.channel.update({ + name: 'Updated Name', + description: 'Testing new description', + url: 'https://google.com', + icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAz0lEQVR4AcXBsU0EQQyG0e+saWJ7oACiKYDMEZVs6GgSpC2BIhzRwAS0sgk9HKn3gpFOAv3v3V4/3+4U4Z1q5KTy42Ql940qvFONnFSGmCFmiN2+fj7uCBlihpgh1ngwcvKfwjuVIWaIGWKNB+GdauSk8uNkJfeNKryzYogZYoZY40m5b/wlQ8wQM8TayMlKeKcaOVkJ71QjJyuGmCFmiDUe+HFy4VyEd57hx0mV+0ZliBlihlgL71w4FyMnVXhnZeSkiu93qheuDDFDzBD7BcCyMAOfy204AAAAAElFTkSuQmCC', + }); + if (showAPIResponse) { + console.log(updatedChannel); + } + console.log('PushAPI.channel.update | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.verify'); + // only verified channels can verify other channels (otherwise this action is skipped by sdk) + if (channelInfo.verified_status) { + const verifiedTrx = await userAlice.channel.verify( + '0x35B84d6848D16415177c64D64504663b998A6ab4' + ); + if (showAPIResponse) { + console.log(verifiedTrx); + } + } + console.log('PushAPI.channel.verify | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.setting'); + const channelSettingTrx = await userAlice.channel.setting([ + { type: 0, default: 1, description: 'My Notif Settings' }, + ]); + if (showAPIResponse) { + console.log(channelSettingTrx); + } + console.log('PushAPI.channel.setting | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.delegate.add'); + const addedDelegate = await userAlice.channel.delegate.add( + `eip155:5:${randomWallet1}` + ); + + if (showAPIResponse) { + console.log(addedDelegate); + } + console.log('PushAPI.channel.delegate.add | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.delegate.get'); + const delegates = await userAlice.channel.delegate.get(); + if (showAPIResponse) { + console.log(delegates); + } + console.log('PushAPI.channel.delegate.get | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.delegate.remove'); + const removedDelegate = await userAlice.channel.delegate.remove( + `eip155:5:${randomWallet1}` + ); + if (showAPIResponse) { + console.log(removedDelegate); + } + console.log('PushAPI.channel.delegate.remove | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.channel.alias.info'); + const aliasInfo = await userAlice.channel.alias.info({ + alias: '0x35B84d6848D16415177c64D64504663b998A6ab4', + aliasChain: 'POLYGON', + }); + if (showAPIResponse) { + console.log(aliasInfo); + } + console.log('PushAPI.channel.alias.info | Response - 200 OK\n\n'); +}; diff --git a/packages/examples/sdk-backend-node/pushAPI/chat.ts b/packages/examples/sdk-backend-node/pushAPI/chat.ts new file mode 100644 index 000000000..f34973ec1 --- /dev/null +++ b/packages/examples/sdk-backend-node/pushAPI/chat.ts @@ -0,0 +1,227 @@ +import { PushAPI } from '@pushprotocol/restapi'; +import { + adjectives, + animals, + colors, + uniqueNamesGenerator, +} from 'unique-names-generator'; +import { config } from '../config'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { createWalletClient, http } from 'viem'; +import { goerli } from 'viem/chains'; + +// CONFIGS +const { env, showAPIResponse } = config; + +/***************** SAMPLE SIGNER GENERATION *********************/ +// Uing VIEM +// Random Wallet Signers +const signer = createWalletClient({ + account: privateKeyToAccount(generatePrivateKey()), + chain: goerli, + transport: http(), +}); +const signerAddress = signer.account.address; +const secondSigner = createWalletClient({ + account: privateKeyToAccount(generatePrivateKey()), + chain: goerli, + transport: http(), +}); +const secondSignerAddress = secondSigner.account.address; +const thirdSigner = createWalletClient({ + account: privateKeyToAccount(generatePrivateKey()), + chain: goerli, + transport: http(), +}); +const thirdSignerAddress = thirdSigner.account.address; + +// Dummy Wallet Addresses +const randomWallet1 = privateKeyToAccount(generatePrivateKey()).address; +const randomWallet2 = privateKeyToAccount(generatePrivateKey()).address; +const randomWallet3 = privateKeyToAccount(generatePrivateKey()).address; +/****************************************************************/ + +/***************** SAMPLE GROUP DATA ****************************/ +const groupName = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], +}); +const groupDescription = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], +}); +const groupImage = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg=='; +/***************** SAMPLE GROUP DATA ****************************/ + +export const runPushAPIChatCases = async (): Promise => { + const userAlice = await PushAPI.initialize(signer, { env }); + const userBob = await PushAPI.initialize(secondSigner, { env }); + const tempUser = await PushAPI.initialize(thirdSigner, { env }); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.chat.list'); + const aliceChats = await userAlice.chat.list('CHATS'); + const aliceRequests = await userAlice.chat.list('REQUESTS'); + if (showAPIResponse) { + console.log(aliceChats); + console.log(aliceRequests); + } + console.log('PushAPI.chat.list | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.chat.latest'); + const aliceLatestChatWithBob = await userAlice.chat.latest( + secondSignerAddress + ); + if (showAPIResponse) { + console.log(aliceLatestChatWithBob); + } + console.log('PushAPI.chat.latest | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.chat.history'); + const aliceChatHistoryWithBob = await userAlice.chat.history( + secondSignerAddress + ); + if (showAPIResponse) { + console.log(aliceChatHistoryWithBob); + } + console.log('PushAPI.chat.history | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.chat.send'); + const aliceMessagesBob = await userAlice.chat.send(secondSignerAddress, { + content: 'Hello Bob!', + type: 'Text', + }); + if (showAPIResponse) { + console.log(aliceMessagesBob); + } + console.log('PushAPI.chat.send | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.chat.accept'); + const bobAcceptsRequest = await userBob.chat.accept(signerAddress); + if (showAPIResponse) { + console.log(bobAcceptsRequest); + } + console.log('PushAPI.chat.accept | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.chat.reject'); + await tempUser.chat.send(secondSignerAddress, { + content: 'Sending malicious message', + type: 'Text', + }); + const bobRejectsRequest = await userBob.chat.reject(thirdSignerAddress); + if (showAPIResponse) { + console.log(bobRejectsRequest); + } + console.log('PushAPI.chat.reject | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.chat.block'); + const AliceBlocksBob = await userAlice.chat.block([secondSignerAddress]); + if (showAPIResponse) { + console.log(AliceBlocksBob); + } + console.log('PushAPI.chat.block | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.chat.unblock'); + const AliceUnblocksBob = await userAlice.chat.unblock([secondSignerAddress]); + if (showAPIResponse) { + console.log(AliceUnblocksBob); + } + console.log('PushAPI.chat.unblock | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.group.create'); + const createdGroup = await userAlice.chat.group.create(groupName, { + description: groupDescription, + image: groupImage, + members: [randomWallet1, randomWallet2], + admins: [], + private: false, + }); + const groupChatId = createdGroup.chatId; // to be used in other examples + if (showAPIResponse) { + console.log(createdGroup); + } + console.log('PushAPI.group.create | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.group.permissions'); + const grouppermissions = await userAlice.chat.group.permissions(groupChatId); + if (showAPIResponse) { + console.log(grouppermissions); + } + console.log('PushAPI.group.permissions | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.group.info'); + const groupInfo = await userAlice.chat.group.info(groupChatId); + if (showAPIResponse) { + console.log(groupInfo); + } + console.log('PushAPI.group.info | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.group.update'); + const updatedGroup = await userAlice.chat.group.update(groupChatId, { + description: 'Updated Description', + }); + if (showAPIResponse) { + console.log(updatedGroup); + } + console.log('PushAPI.group.update | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.group.add'); + const addMember = await userAlice.chat.group.add(groupChatId, { + role: 'MEMBER', + accounts: [randomWallet3], + }); + if (showAPIResponse) { + console.log(addMember); + } + console.log('PushAPI.group.add | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.group.remove'); + const removeMember = await userAlice.chat.group.remove(groupChatId, { + role: 'MEMBER', + accounts: [randomWallet3], + }); + if (showAPIResponse) { + console.log(removeMember); + } + console.log('PushAPI.group.remove | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.group.join'); + const joinGrp = await userBob.chat.group.join(groupChatId); + if (showAPIResponse) { + console.log(joinGrp); + } + console.log('PushAPI.group.join | Response - 200 OK\n\n'); + //------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.group.leave'); + const leaveGrp = await userBob.chat.group.leave(groupChatId); + if (showAPIResponse) { + console.log(leaveGrp); + } + console.log('PushAPI.group.leave | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.group.reject'); + const sampleGrp = await userAlice.chat.group.create('Sample Grp', { + description: groupDescription, + image: groupImage, + members: [secondSignerAddress], // invite bob + admins: [], + private: true, + }); + await userBob.chat.group.reject(sampleGrp.chatId); + console.log('PushAPI.group.reject | Response - 200 OK\n\n'); +}; diff --git a/packages/examples/sdk-backend-node/pushAPI/encryption.ts b/packages/examples/sdk-backend-node/pushAPI/encryption.ts new file mode 100644 index 000000000..67300c65f --- /dev/null +++ b/packages/examples/sdk-backend-node/pushAPI/encryption.ts @@ -0,0 +1,38 @@ +import { PushAPI } from '@pushprotocol/restapi'; +import { config } from '../config'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { createWalletClient, http } from 'viem'; +import { goerli } from 'viem/chains'; + +// CONFIGS +const { env, showAPIResponse } = config; + +/***************** SAMPLE SIGNER GENERATION *********************/ +// Uing VIEM +// Random Wallet Signers +const signer = createWalletClient({ + account: privateKeyToAccount(generatePrivateKey()), + chain: goerli, + transport: http(), +}); + +export const runPushAPIEncryptionCases = async (): Promise => { + const userAlice = await PushAPI.initialize(signer, { env }); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.encryption.info'); + const encryptionInfo = await userAlice.encryption.info(); + if (showAPIResponse) { + console.log(encryptionInfo); + } + console.log('PushAPI.encryption.info | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.encryption.update'); + const PGP_V3 = 'eip191-aes256-gcm-hkdf-sha256'; + const encryptionUpdate = await userAlice.encryption.update(PGP_V3 as any); + if (showAPIResponse) { + console.log(encryptionUpdate); + } + console.log('PushAPI.encryption.update | Response - 200 OK\n\n'); +}; diff --git a/packages/examples/sdk-backend-node/pushAPI/index.ts b/packages/examples/sdk-backend-node/pushAPI/index.ts index 2b02dca10..c6a58dde5 100644 --- a/packages/examples/sdk-backend-node/pushAPI/index.ts +++ b/packages/examples/sdk-backend-node/pushAPI/index.ts @@ -1,15 +1,14 @@ import { PushAPI } from '@pushprotocol/restapi'; -import { - adjectives, - animals, - colors, - uniqueNamesGenerator, -} from 'unique-names-generator'; import { config } from '../config'; import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; import { createWalletClient, http } from 'viem'; import { goerli } from 'viem/chains'; -import { createSocketConnection, EVENTS } from '@pushprotocol/socket'; +import { runPushAPIChatCases } from './chat'; +import { runPushAPIEncryptionCases } from './encryption'; +import { runPushAPINotificationCases } from './notification'; +import { runPushAPIProfileCases } from './profile'; +import { runPushAPIStreamCases } from './stream'; +import { runPushAPIChannelCases } from './channel'; // CONFIGS const { env, showAPIResponse } = config; @@ -22,35 +21,6 @@ const signer = createWalletClient({ chain: goerli, transport: http(), }); -const signerAddress = signer.account.address; -const secondSigner = createWalletClient({ - account: privateKeyToAccount(generatePrivateKey()), - chain: goerli, - transport: http(), -}); -const secondSignerAddress = secondSigner.account.address; -const thirdSigner = createWalletClient({ - account: privateKeyToAccount(generatePrivateKey()), - chain: goerli, - transport: http(), -}); -const thirdSignerAddress = thirdSigner.account.address; -// Dummy Wallet Addresses -const randomWallet1 = privateKeyToAccount(generatePrivateKey()).address; -const randomWallet2 = privateKeyToAccount(generatePrivateKey()).address; -const randomWallet3 = privateKeyToAccount(generatePrivateKey()).address; -/****************************************************************/ - -/***************** SAMPLE GROUP DATA ****************************/ -const groupName = uniqueNamesGenerator({ - dictionaries: [adjectives, colors, animals], -}); -const groupDescription = uniqueNamesGenerator({ - dictionaries: [adjectives, colors, animals], -}); -const groupImage = - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg=='; -/***************** SAMPLE GROUP DATA ****************************/ export const runPushAPICases = async (): Promise => { console.log(` @@ -66,10 +36,10 @@ export const runPushAPICases = async (): Promise => { // ------------------------------------------------------------------- console.log('PushAPI.initialize'); const userAlice = await PushAPI.initialize(signer, { env }); - const userBob = await PushAPI.initialize(secondSigner, { env }); console.log('PushAPI.initialize | Response - 200 OK\n\n'); // ------------------------------------------------------------------- // ------------------------------------------------------------------- + // todo : This is yet to be discussed console.log('PushAPI.info'); const userAliceInfo = await userAlice.user.info(); if (showAPIResponse) { @@ -78,228 +48,10 @@ export const runPushAPICases = async (): Promise => { console.log('PushAPI.info | Response - 200 OK\n\n'); // ------------------------------------------------------------------- // ------------------------------------------------------------------- - console.log('PushAPI.profile.info'); - const userAliceProfileInfo = await userAlice.profile.info(); - if (showAPIResponse) { - console.log(userAliceProfileInfo); - } - console.log('PushAPI.profile.info | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.profile.update'); - const updatedName = 'Bob The Builder'; - const response = await userAlice.profile.update({ name: updatedName }); - if (showAPIResponse) { - console.log(response); - } - console.log('PushAPI.profile.update | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.chat.list'); - const aliceChats = await userAlice.chat.list('CHATS'); - const aliceRequests = await userAlice.chat.list('REQUESTS'); - if (showAPIResponse) { - console.log(aliceChats); - console.log(aliceRequests); - } - console.log('PushAPI.chat.list | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.chat.latest'); - const aliceLatestChatWithBob = await userAlice.chat.latest( - secondSignerAddress - ); - if (showAPIResponse) { - console.log(aliceLatestChatWithBob); - } - console.log('PushAPI.chat.latest | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.chat.history'); - const aliceChatHistoryWithBob = await userAlice.chat.history( - secondSignerAddress - ); - if (showAPIResponse) { - console.log(aliceChatHistoryWithBob); - } - console.log('PushAPI.chat.history | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.chat.send'); - const aliceMessagesBob = await userAlice.chat.send(secondSignerAddress, { - content: 'Hello Bob!', - type: 'Text', - }); - if (showAPIResponse) { - console.log(aliceMessagesBob); - } - console.log('PushAPI.chat.send | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.chat.decrypt'); - const pushSDKSocket = createSocketConnection({ - user: signerAddress, - socketType: 'chat', - socketOptions: { autoConnect: true, reconnectionAttempts: 3 }, - env: env, - }); - if (pushSDKSocket) { - await userAlice.chat.send(secondSignerAddress, { - content: 'Hello Bob!', - type: 'Text', - }); - pushSDKSocket.on(EVENTS.CHAT_RECEIVED_MESSAGE, async (message) => { - // uncomment after latest sdk deployment - // await userAlice.chat.decrypt([message]); - // pushSDKSocket.disconnect(); - }); - } - console.log('PushAPI.chat.decrypt | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.chat.accept'); - const bobAcceptsRequest = await userBob.chat.accept(signerAddress); - if (showAPIResponse) { - console.log(bobAcceptsRequest); - } - console.log('PushAPI.chat.accept | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.chat.reject'); - const tempUser = await PushAPI.initialize(thirdSigner, { env }); - await tempUser.chat.send(secondSignerAddress, { - content: 'Sending Malicious message to bob', - }); - const bobRejectsRequest = await userBob.chat.reject(thirdSignerAddress); - if (showAPIResponse) { - console.log(bobRejectsRequest); - } - console.log('PushAPI.chat.reject | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.chat.block'); - const AliceBlocksBob = await userAlice.chat.block([secondSignerAddress]); - if (showAPIResponse) { - console.log(AliceBlocksBob); - } - console.log('PushAPI.chat.block | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.chat.unblock'); - const AliceUnblocksBob = await userAlice.chat.unblock([secondSignerAddress]); - if (showAPIResponse) { - console.log(AliceUnblocksBob); - } - console.log('PushAPI.chat.unblock | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.group.create'); - const createdGroup = await userAlice.chat.group.create(groupName, { - description: groupDescription, - image: groupImage, - members: [randomWallet1, randomWallet2], - admins: [], - private: false, - }); - const groupChatId = createdGroup.chatId; // to be used in other examples - if (showAPIResponse) { - console.log(createdGroup); - } - console.log('PushAPI.group.create | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.group.permissions'); - const grouppermissions = await userAlice.chat.group.permissions(groupChatId); - if (showAPIResponse) { - console.log(grouppermissions); - } - console.log('PushAPI.group.permissions | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.group.info'); - const groupInfo = await userAlice.chat.group.info(groupChatId); - if (showAPIResponse) { - console.log(groupInfo); - } - console.log('PushAPI.group.info | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.group.update'); - const updatedGroup = await userAlice.chat.group.update(groupChatId, { - description: 'Updated Description', - }); - if (showAPIResponse) { - console.log(updatedGroup); - } - console.log('PushAPI.group.update | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.group.add'); - const addMember = await userAlice.chat.group.add(groupChatId, { - role: 'MEMBER', - accounts: [randomWallet3], - }); - if (showAPIResponse) { - console.log(addMember); - } - console.log('PushAPI.group.add | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.group.remove'); - const removeMember = await userAlice.chat.group.remove(groupChatId, { - role: 'MEMBER', - accounts: [randomWallet3], - }); - if (showAPIResponse) { - console.log(removeMember); - } - console.log('PushAPI.group.remove | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.group.join'); - const joinGrp = await userBob.chat.group.join(groupChatId); - if (showAPIResponse) { - console.log(joinGrp); - } - console.log('PushAPI.group.join | Response - 200 OK\n\n'); - //------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.group.leave'); - const leaveGrp = await userBob.chat.group.leave(groupChatId); - if (showAPIResponse) { - console.log(leaveGrp); - } - console.log('PushAPI.group.leave | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.group.reject'); - const sampleGrp = await userAlice.chat.group.create('Sample Grp', { - description: groupDescription, - image: groupImage, - members: [secondSignerAddress], // invite bob - admins: [], - private: true, - }); - const rejectGrpJoiningReq = await userBob.chat.group.reject(sampleGrp.chatId); - if (showAPIResponse) { - console.log(rejectGrpJoiningReq); - } - console.log('PushAPI.group.reject | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.encryption.info'); - const encryptionInfo = await userAlice.encryption.info(); - if (showAPIResponse) { - console.log(encryptionInfo); - } - console.log('PushAPI.encryption.info | Response - 200 OK\n\n'); - // ------------------------------------------------------------------- - // ------------------------------------------------------------------- - console.log('PushAPI.encryption.update'); - const PGP_V3 = 'eip191-aes256-gcm-hkdf-sha256'; - const encryptionUpdate = await userAlice.encryption.update(PGP_V3 as any); - if (showAPIResponse) { - console.log(encryptionUpdate); - } - console.log('PushAPI.encryption.update | Response - 200 OK\n\n'); + await runPushAPIProfileCases(); // PushAPI.profile + await runPushAPIChatCases(); // PushAPI.chat + await runPushAPIEncryptionCases(); // PushAPI.encryption + await runPushAPINotificationCases(); // PushAPI.notification + await runPushAPIChannelCases(); // PushAPI.channel + await runPushAPIStreamCases(); // PushAPI.stream }; diff --git a/packages/examples/sdk-backend-node/pushAPI/notification.ts b/packages/examples/sdk-backend-node/pushAPI/notification.ts new file mode 100644 index 000000000..579ea1e2b --- /dev/null +++ b/packages/examples/sdk-backend-node/pushAPI/notification.ts @@ -0,0 +1,58 @@ +import { PushAPI } from '@pushprotocol/restapi'; +import { config } from '../config'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { createWalletClient, http } from 'viem'; +import { goerli } from 'viem/chains'; + +// CONFIGS +const { env, showAPIResponse } = config; + +/***************** SAMPLE SIGNER GENERATION *********************/ +// Uing VIEM +// Random Wallet Signers +const signer = createWalletClient({ + account: privateKeyToAccount(generatePrivateKey()), + chain: goerli, + transport: http(), +}); + +export const runPushAPINotificationCases = async (): Promise => { + const userAlice = await PushAPI.initialize(signer, { env }); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.notification.list'); + const inboxNotifications = await userAlice.notification.list('INBOX'); + const spamNotifications = await userAlice.notification.list('SPAM'); + if (showAPIResponse) { + console.log(inboxNotifications, spamNotifications); + } + console.log('PushAPI.notification.list | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.notification.subscribe'); + const subscribeResponse = await userAlice.notification.subscribe( + 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681' // channel to subscribe + ); + if (showAPIResponse) { + console.log(subscribeResponse); + } + console.log('PushAPI.notification.subscribe | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.notification.subscriptions'); + const aliceSubscriptions = await userAlice.notification.subscriptions(); + if (showAPIResponse) { + console.log(aliceSubscriptions); + } + console.log('PushAPI.notification.subscriptions | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.notification.unsubscribe'); + const unsubscribeResponse = await userAlice.notification.unsubscribe( + 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681' // channel to unsubscribe + ); + if (showAPIResponse) { + console.log(unsubscribeResponse); + } + console.log('PushAPI.notification.unsubscribe | Response - 200 OK\n\n'); +}; diff --git a/packages/examples/sdk-backend-node/pushAPI/profile.ts b/packages/examples/sdk-backend-node/pushAPI/profile.ts new file mode 100644 index 000000000..f72d93f1b --- /dev/null +++ b/packages/examples/sdk-backend-node/pushAPI/profile.ts @@ -0,0 +1,38 @@ +import { PushAPI } from '@pushprotocol/restapi'; +import { config } from '../config'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { createWalletClient, http } from 'viem'; +import { goerli } from 'viem/chains'; + +// CONFIGS +const { env, showAPIResponse } = config; + +/***************** SAMPLE SIGNER GENERATION *********************/ +// Uing VIEM +// Random Wallet Signers +const signer = createWalletClient({ + account: privateKeyToAccount(generatePrivateKey()), + chain: goerli, + transport: http(), +}); + +export const runPushAPIProfileCases = async (): Promise => { + const userAlice = await PushAPI.initialize(signer, { env }); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.profile.info'); + const userAliceProfileInfo = await userAlice.profile.info(); + if (showAPIResponse) { + console.log(userAliceProfileInfo); + } + console.log('PushAPI.profile.info | Response - 200 OK\n\n'); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('PushAPI.profile.update'); + const updatedName = 'Bob The Builder'; + const response = await userAlice.profile.update({ name: updatedName }); + if (showAPIResponse) { + console.log(response); + } + console.log('PushAPI.profile.update | Response - 200 OK\n\n'); +}; diff --git a/packages/examples/sdk-backend-node/pushAPI/stream.ts b/packages/examples/sdk-backend-node/pushAPI/stream.ts new file mode 100644 index 000000000..e10c599c8 --- /dev/null +++ b/packages/examples/sdk-backend-node/pushAPI/stream.ts @@ -0,0 +1,202 @@ +import { PushAPI } from '@pushprotocol/restapi'; +import { config } from '../config'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { createWalletClient, http } from 'viem'; +import { goerli } from 'viem/chains'; +import { STREAM } from '@pushprotocol/restapi/src/lib/pushstream/pushStreamTypes'; + +// CONFIGS +const { env, showAPIResponse } = config; + +/***************** SAMPLE SIGNER GENERATION *********************/ +// Uing VIEM +// Random Wallet Signers +const signer = createWalletClient({ + account: privateKeyToAccount(generatePrivateKey()), + chain: goerli, + transport: http(), +}); +const signerAddress = signer.account.address; +const secondSigner = createWalletClient({ + account: privateKeyToAccount(generatePrivateKey()), + chain: goerli, + transport: http(), +}); +const secondSignerAddress = secondSigner.account.address; +const thirdSigner = createWalletClient({ + account: privateKeyToAccount(generatePrivateKey()), + chain: goerli, + transport: http(), +}); +const thirdSignerAddress = thirdSigner.account.address; +// Dummy Wallet Addresses +const randomWallet1 = privateKeyToAccount(generatePrivateKey()).address; + +const eventlistener = async ( + pushAPI: PushAPI, + eventName: string +): Promise => { + pushAPI.stream.on(eventName, (data: any) => { + if (showAPIResponse) { + console.log(data); + } + }); +}; + +const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +export const runPushAPIStreamCases = async (): Promise => { + const userAlice = await PushAPI.initialize(signer, { env }); + const userBob = await PushAPI.initialize(secondSigner, { env }); + const userKate = await PushAPI.initialize(thirdSigner, { env }); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log(`Listening ${STREAM.PROFILE} Events`); + eventlistener(userAlice, STREAM.PROFILE); + console.log(`Listening ${STREAM.ENCRYPTION} Events`); + eventlistener(userAlice, STREAM.ENCRYPTION); + console.log(`Listening ${STREAM.NOTIF} Events`); + eventlistener(userAlice, STREAM.NOTIF); + console.log(`Listening ${STREAM.NOTIF_OPS} Events`); + eventlistener(userAlice, STREAM.NOTIF_OPS); + console.log(`Listening ${STREAM.CHAT} Events`); + eventlistener(userAlice, STREAM.CHAT); + console.log(`Listening ${STREAM.CHAT_OPS} Events`); + eventlistener(userAlice, STREAM.CHAT_OPS); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('\n\nNew Chat Request, Expected Events:\n1. chat.request'); + await userAlice.chat.send(secondSignerAddress, { + content: 'Hello Bob! from Alice', + }); + await delay(3000); // Delay added to log the events in order + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('\n\nNew Chat Request, Expected Events:\n1. chat.request'); + await userAlice.chat.send(thirdSignerAddress, { + content: 'Hello Kate! from Alice', + }); + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('\n\nChat Request Accept, Expected Events:\n1. chat.accept'); + await userBob.chat.accept(signerAddress); + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('\n\nChat Request Reject, Expected Events:\n1. chat.reject'); + await userKate.chat.reject(signerAddress); + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('\n\nCreate Chat Group, Expected Events:\n1. chat.group.create'); + const groupChatId = ( + await userAlice.chat.group.create('Test Grp', { + description: 'Test Desc', + image: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg==', + members: [secondSignerAddress, thirdSignerAddress], + admins: [], + private: false, + }) + ).chatId; + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('\n\nUpdate Chat Group, Expected Events:\n1. chat.group.update'); + await userAlice.chat.group.update(groupChatId, { + description: 'Updated Test Desc', + image: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg==', + }); + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('\n\nAdd member to Group, Expected Events:\n1. chat.request'); + await userAlice.chat.group.add(groupChatId, { + role: 'MEMBER', + accounts: [randomWallet1], + }); + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log( + '\n\nRemove member from Group, Expected Events:\n1. chat.group.participant.remove' + ); + await userAlice.chat.group.remove(groupChatId, { + role: 'MEMBER', + accounts: [randomWallet1], + }); + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('\n\nAdd Admin to Group, Expected Events:\n1. chat.request'); + await userAlice.chat.group.add(groupChatId, { + role: 'ADMIN', + accounts: [randomWallet1], + }); + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log( + '\n\nRemove Admin from Group, Expected Events:\n1. chat.group.participant.remove' + ); + await userAlice.chat.group.remove(groupChatId, { + role: 'ADMIN', + accounts: [randomWallet1], + }); + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log('\n\nJoin Group, Expected Events:\n1. chat.accept'); + await userBob.chat.group.join(groupChatId); + await delay(3000); + //------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log( + '\n\nLeave Group, Expected Events:\n1. chat.group.participant.leave' + ); + await userBob.chat.group.leave(groupChatId); + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + console.log( + '\n\nReject Group Joining Request, Expected Events:\n1. chat.reject' + ); + await userKate.chat.group.reject(groupChatId); + await delay(3000); + // ------------------------------------------------------------------- + // ------------------------------------------------------------------- + if (process.env.WALLET_PRIVATE_KEY) { + // create signer + const channelSigner = createWalletClient({ + account: privateKeyToAccount(`0x${process.env.WALLET_PRIVATE_KEY}`), + chain: goerli, + transport: http(), + }); + + await userAlice.notification.subscribe( + `eip155:5:${channelSigner.account.address}` // channel to subscribe + ); + + const channelUser = await PushAPI.initialize(channelSigner, { env }); + console.log( + '\n\nSend channel notification, Expected Events:\n1. notif.send' + ); + await channelUser.channel.send(['*'], { + notification: { + title: 'test', + body: 'test', + }, + }); + await delay(3000); + + await userAlice.notification.unsubscribe( + `eip155:5:${channelSigner.account.address}` // channel to subscribe + ); + } else { + console.log( + 'Skipping channel notification streams, as WALLET_PRIVATE_KEY is not present in .env' + ); + } +}; diff --git a/packages/examples/sdk-backend-node/video/index.ts b/packages/examples/sdk-backend-node/video/index.ts index 209522514..e9202c387 100644 --- a/packages/examples/sdk-backend-node/video/index.ts +++ b/packages/examples/sdk-backend-node/video/index.ts @@ -21,14 +21,14 @@ const videoSetData: ( let videoObject: any = null; const videoLocalStream = null; // get the local stream const videoSenderAddress = process.env.VIDEO_SENDER_ADDRESS; -const videoRecipientAddress = process.env.VIDEO_RECIPEINT_ADDRESS; +const videoRecipientAddress = process.env.VIDEO_RECIPIENT_ADDRESS; const videoChatId = process.env.VIDEO_CHAT_ID; let videoSignalData_1: any = null; const skipExample = () => { const requiredEnvVars = [ 'VIDEO_SENDER_ADDRESS', - 'VIDEO_RECIPEINT_ADDRESS', + 'VIDEO_RECIPIENT_ADDRESS', 'VIDEO_CHAT_ID', 'VIDEO_CHAIN_ID', ]; diff --git a/packages/examples/sdk-frontend-react/src/app/components/Connect.tsx b/packages/examples/sdk-frontend-react/src/app/components/Connect.tsx index 1041ea25b..cc5b89378 100644 --- a/packages/examples/sdk-frontend-react/src/app/components/Connect.tsx +++ b/packages/examples/sdk-frontend-react/src/app/components/Connect.tsx @@ -19,10 +19,12 @@ const NETWORK_MAPPING: NwMappingType = { 10: 'OPTIMISM_MAINNET', 1442: 'POLYGON_ZK_EVM_TESTNET', 1101: 'POLYGON_ZK_EVM_MAINNET', + 421613: "ARBITRUM_TESTNET", + 42161: "ARBITRUMONE_MAINNET" }; const injected = new InjectedConnector({ - supportedChainIds: [1, 3, 4, 5, 42, 137, 80001, 56, 97, 10, 420, 1442, 1101], + supportedChainIds: [1, 3, 4, 5, 42, 137, 80001, 56, 97, 10, 420, 1442, 1101, 421613, 42161], }); const ConnectWrapper = styled.div` diff --git a/packages/examples/sdk-frontend-react/src/app/helpers.ts b/packages/examples/sdk-frontend-react/src/app/helpers.ts index d5af6bc15..bad12f49d 100644 --- a/packages/examples/sdk-frontend-react/src/app/helpers.ts +++ b/packages/examples/sdk-frontend-react/src/app/helpers.ts @@ -18,7 +18,7 @@ const Constants = { }, DEFAULT_CHAIN_ID: 5, DEV_CHAIN_ID: 99999, - NON_ETH_CHAINS: [137, 80001, 56, 97, 10, 420, 1442, 1101], + NON_ETH_CHAINS: [137, 80001, 56, 97, 10, 420, 1442, 1101, 421613, 42161], ETH_CHAINS: [1, 5], }; diff --git a/packages/reactnative/README.md b/packages/reactnative/README.md index 4eae3bfa0..d3e665c64 100644 --- a/packages/reactnative/README.md +++ b/packages/reactnative/README.md @@ -208,5 +208,5 @@ where | cta | string | Call To Action Link (given during notification creation) | | image | string | Any media link (given during notification creation) | | appbot | string | is the notification is from EPNS bot the value is "1" else "0" | -| chainName | string | Can be anyone of the following blockchain networks on which the notification was sent - "ETH_MAINNET", "ETH_TEST_GOERLI", "POLYGON_MAINNET", "POLYGON_TEST_MUMBAI", "BSC_MAINNET, "BSC_TESTNET", "OPTIMISM_MAINNET", "OPTIMISM_TESTNET", "POLYGON_ZK_EVM_TESTNET", "POLYGON_ZK_EVM_MAINNET", "THE_GRAPH" | +| chainName | string | Can be anyone of the following blockchain networks on which the notification was sent - "ETH_MAINNET", "ETH_TEST_GOERLI", "POLYGON_MAINNET", "POLYGON_TEST_MUMBAI", "BSC_MAINNET, "BSC_TESTNET", "OPTIMISM_MAINNET", "OPTIMISM_TESTNET", "POLYGON_ZK_EVM_TESTNET", "POLYGON_ZK_EVM_MAINNET", "ARBITRUM_TESTNET", "ARBITRUMONE_MAINNET", "THE_GRAPH" | | youTubeAPIKey | string | Your generated Youtube API key | \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/chainDetails/arbitrumSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/arbitrumSVG.tsx new file mode 100644 index 000000000..7106c3552 --- /dev/null +++ b/packages/reactnative/src/lib/components/chainDetails/arbitrumSVG.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; +import { SVGProps } from 'react'; + +const ArbitrumSvgComponent = (props: SVGProps) => ( + + + + + + + +); + +export default ArbitrumSvgComponent; diff --git a/packages/reactnative/src/lib/components/chainDetails/index.tsx b/packages/reactnative/src/lib/components/chainDetails/index.tsx index 08c8cb55b..dbd6c8e19 100644 --- a/packages/reactnative/src/lib/components/chainDetails/index.tsx +++ b/packages/reactnative/src/lib/components/chainDetails/index.tsx @@ -3,9 +3,15 @@ import PolygonSvg from "./polygonSVG"; import GraphSvg from "./thegraphSVG"; import BscSvg from "./bscSVG"; import OptimismSvg from "./optimismSVG" -import PolygonZKEVMSvg from "./polygonZKEVMSVG"; +import PolygonZKEVMSvg from "./polygonZkEVMSVG"; +import ArbitrumSvgComponent from "./arbitrumSVG"; -export default { +type Network = { + label: string; + Icon: any; +}; + +const networks: Record = { ETH_TEST_GOERLI: { label: "ETHEREUM GOERLI", Icon: EthereumSvg }, ETH_MAINNET: { label: "ETHEREUM MAINNET", Icon: EthereumSvg }, POLYGON_TEST_MUMBAI: { label: "POLYGON MUMBAI", Icon: PolygonSvg }, @@ -16,5 +22,9 @@ export default { OPTIMISM_MAINNET: { label: "OPTIMISM MAINNET", Icon: OptimismSvg }, POLYGON_ZK_EVM_TESTNET: {label:"POLYGON_ZK_EVM_TESTNET",Icon: PolygonZKEVMSvg}, POLYGON_ZK_EVM_MAINNET: {label:"POLYGON_ZK_EVM_MAINNET",Icon: PolygonZKEVMSvg}, + ARBITRUM_TESTNET: {label:"ARBITRUM_TESTNET",Icon: ArbitrumSvgComponent}, + ARBITRUMONE_MAINNET: {label: "ARBITRUMONE_MAINNET", Icon: ArbitrumSvgComponent}, THE_GRAPH: { label: "THE GRAPH", Icon: GraphSvg }, -}; \ No newline at end of file +}; + +export default networks \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/notifications/notification.tsx b/packages/reactnative/src/lib/components/notifications/notification.tsx index 30869655e..bbc064056 100644 --- a/packages/reactnative/src/lib/components/notifications/notification.tsx +++ b/packages/reactnative/src/lib/components/notifications/notification.tsx @@ -18,7 +18,7 @@ import { ImageDownloadWithIndicator, VideoDownloadWithIndicator } from '../load // ================= Define types -export type chainNameType = "ETH_TEST_GOERLI" | "POLYGON_TEST_MUMBAI" | "ETH_MAINNET" | "POLYGON_MAINNET" | "BSC_MAINNET" | "BSC_TESTNET" | "OPTIMISM_MAINNET" | "OPTIMISM_TESTNET" | "POLYGON_ZK_EVM_TESTNET" | "POLYGON_ZK_EVM_MAINNET" | "THE_GRAPH" | undefined; +export type chainNameType = "ETH_TEST_GOERLI" | "POLYGON_TEST_MUMBAI" | "ETH_MAINNET" | "POLYGON_MAINNET" | "BSC_MAINNET" | "BSC_TESTNET" | "OPTIMISM_MAINNET" | "OPTIMISM_TESTNET" | "POLYGON_ZK_EVM_TESTNET" | "POLYGON_ZK_EVM_MAINNET" | "ARBITRUMONE_MAINNET" | "ARBITRUM_TESTNET" | "THE_GRAPH" | undefined; const botImageLocalPath = '../../assets/epnsbot.png'; diff --git a/packages/restapi/README.md b/packages/restapi/README.md index 1aa9dffde..1c51666e1 100644 --- a/packages/restapi/README.md +++ b/packages/restapi/README.md @@ -181,6 +181,8 @@ Binance Mainnet - 0xb3971BCef2D791bc4027BbfedFb47319A4AAaaAa Binance Testnet - 0xb3971BCef2D791bc4027BbfedFb47319A4AAaaAa Optimism Mainnet - 0xb3971BCef2D791bc4027BbfedFb47319A4AAaaAa Optimism Testnet - 0xb3971BCef2D791bc4027BbfedFb47319A4AAaaAa +Arbitrum Mainnet - 0xb3971BCef2D791bc4027BbfedFb47319A4AAaaAa +Arbitrum One Testnet - 0xb3971BCef2D791bc4027BbfedFb47319A4AAaaAa ``` # SDK Features @@ -4567,15 +4569,14 @@ const aliceMessagesBob = await userAlice.chat.send(bobAddress, { }); ``` -| Param | Type | Default | Remarks | -| ---------------------- | ---------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------- | -| `recipient` | `string` | - | Recipient ( For Group Chats target is chatId, for 1 To 1 chat target is Push DID ) | -| `options` | `object` | - | Configuration for message to be sent | -| `options.type` \* | `Text` or `Image` or `File` or `MediaEmbed` or `GIF` or `Meta` or `Reaction` | - | Type of message Content | -| `options.content` | `string` | - | Message Content | -| `options.action` \* | `string` | - | Message action ( Only available for Meta & Reaction Messages ) | -| `options.reference` \* | `string` or `null` | - | Message reference hash ( Only available for Reaction Messages ) | -| `options.info` \* | `{ affected : string[]: arbitrary?: { [key: string]: any } }` | - | Message reference hash ( Only available for Meta Messages ) | +| Param | Type | Default | Remarks | +| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------- | +| `recipient` | `string` | - | Recipient ( For Group Chats target is chatId, for 1 To 1 chat target is Push DID ) | +| `options` | `object` | - | Configuration for message to be sent | +| `options.type` \* | `Text` or `Image` or `Audio` or `Video` or `File` or `MediaEmbed` or `GIF` or `Meta` or `Reaction` or `Receipt` or `Intent` or `Reply` or `Composite` | - | Type of message Content | +| `options.content` | `string` or `{type: `Text`or`Image`or`Audio`or`Video`or`File`or`MediaEmbed`or`GIF` ; content: string}` [For Reply] or `{type: `Text`or`Image`or`Audio`or`Video`or`File`or`MediaEmbed`or`GIF` ; content: string}[]` [For Composite] | - | Message Content | +| `options.reference` \* | `string` | - | Message reference hash ( Only available for Reaction & Reply Messages ) | +| `options.info` \* | `{ affected : string[]: arbitrary?: { [key: string]: any } }` | - | Message reference hash ( Only available for Meta & UserActivity Messages ) | \* - Optional diff --git a/packages/restapi/src/lib/chat/send.ts b/packages/restapi/src/lib/chat/send.ts index 30a396495..095f0fa73 100644 --- a/packages/restapi/src/lib/chat/send.ts +++ b/packages/restapi/src/lib/chat/send.ts @@ -11,16 +11,8 @@ import { import { conversationHash } from './conversationHash'; import { ISendMessagePayload, sendMessagePayload } from './helpers'; import { getGroup } from './getGroup'; -import { - MessageObj, - REACTION_SYMBOL, - ReactionMessage, -} from '../types/messageTypes'; -import { - messageObjSchema, - metaMessageObjSchema, - reationMessageObjSchema, -} from '../validations/messageObject'; +import { MessageObj } from '../types/messageTypes'; +import { validateMessageObj } from '../validations/messageObject'; /** * SENDS A PUSH CHAT MESSAGE @@ -54,14 +46,18 @@ export const send = async ( }) : null; - // OVERRIDE CONTENT FOR REACTION MESSAGE - if (messageType === MessageType.REACTION) { - messageObj.content = - REACTION_SYMBOL[(messageObj as Omit).action]; + // Not supported by legacy sdk versions, need to override messageContent to avoid parsing errors on legacy sdk versions + let messageContent: string; + if ( + messageType === MessageType.REPLY || + messageType === MessageType.COMPOSITE + ) { + messageContent = + 'MessageType Not Supported by this sdk version. Plz upgrade !!!'; + } else { + messageContent = messageObj.content as string; } - const messageContent = messageObj.content; // provide backward compatibility & override deprecated field - const conversationResponse = await conversationHash({ conversationId: receiver, account: sender.did, @@ -138,36 +134,7 @@ const validateOptions = async (options: ComputedOptionsType) => { } } - if ( - messageType === MessageType.TEXT || - messageType === MessageType.IMAGE || - messageType === MessageType.FILE || - messageType === MessageType.MEDIA_EMBED || - messageType === MessageType.GIF - ) { - const { error } = messageObjSchema.validate(messageObj); - if (error) { - throw new Error( - `Unable to parse this messageType. Please ensure 'messageObj' is properly defined.` - ); - } - } - - if (messageType === MessageType.META) { - const { error } = metaMessageObjSchema.validate(messageObj); - if (error) { - throw new Error( - `Unable to parse this messageType. Please ensure 'messageObj' is properly defined.` - ); - } - } else if (messageType === MessageType.REACTION) { - const { error } = reationMessageObjSchema.validate(messageObj); - if (error) { - throw new Error( - `Unable to parse this messageType. Please ensure 'messageObj' is properly defined.` - ); - } - } + validateMessageObj(messageObj, messageType); }; const computeOptions = (options: ChatSendOptionsType): ComputedOptionsType => { @@ -203,6 +170,36 @@ const computeOptions = (options: ChatSendOptionsType): ComputedOptionsType => { messageObj = rest; } + // Parse Reply Message + if (messageType === MessageType.REPLY) { + if (typeof messageObj.content === 'object') { + const { type, ...rest } = messageObj.content; + messageObj.content = { + messageType: type, + messageObj: rest, + }; + } else { + throw new Error('Options.message is not properly defined for Reply'); + } + } + + // Parse Composite Message + if (messageType === MessageType.COMPOSITE) { + if (messageObj.content instanceof Array) { + messageObj.content = messageObj.content.map( + (obj: { type: string; content: string }) => { + const { type, ...rest } = obj; + return { + messageType: type, + messageObj: rest, + }; + } + ); + } else { + throw new Error('Options.message is not properly defined for Composite'); + } + } + const account = options.account !== undefined ? options.account : null; const to = options.to !== undefined ? options.to : options.receiverAddress; diff --git a/packages/restapi/src/lib/config.ts b/packages/restapi/src/lib/config.ts index e597c22bc..36f9e6ddc 100644 --- a/packages/restapi/src/lib/config.ts +++ b/packages/restapi/src/lib/config.ts @@ -39,9 +39,11 @@ const BLOCKCHAIN_NETWORK = { OPTIMISM_MAINNET: 'eip155:10', POLYGON_ZK_EVM_TESTNET: 'eip155:1442', POLYGON_ZK_EVM_MAINNET: 'eip155:1101', + ARBITRUM_TESTNET: 'eip155:421613', + ARBITRUMONE_MAINNET: "eip155:42161" }; -export type ALIAS_CHAIN = 'POLYGON' | 'BSC' | 'OPTIMISM' | 'POLYGONZKEVM'; +export type ALIAS_CHAIN = 'POLYGON' | 'BSC' | 'OPTIMISM' | 'POLYGONZKEVM' | "ARBITRUMONE"; export const ETH_CHAIN_ID = { [ENV.PROD]: 1, @@ -74,6 +76,12 @@ export const ALIAS_CHAIN_ID = { [ENV.DEV]: 1442, [ENV.LOCAL]: 1442, }, + ARBITRUMONE: { + [ENV.PROD]: 42161, + [ENV.STAGING]: 421613, + [ENV.DEV]: 421613, + [ENV.LOCAL]: 421613, + } }; export const CHAIN_ID = { @@ -168,6 +176,10 @@ const CONFIG = { API_BASE_URL: API_BASE_URL[ENV.PROD], EPNS_COMMUNICATOR_CONTRACT: '0xb3971BCef2D791bc4027BbfedFb47319A4AAaaAa', }, + [BLOCKCHAIN_NETWORK.ARBITRUMONE_MAINNET]: { + API_BASE_URL: API_BASE_URL[ENV.PROD], + EPNS_COMMUNICATOR_CONTRACT: '0xb3971BCef2D791bc4027BbfedFb47319A4AAaaAa', + }, }, [ENV.STAGING]: { [BLOCKCHAIN_NETWORK.ETH_GOERLI]: { @@ -190,6 +202,10 @@ const CONFIG = { API_BASE_URL: API_BASE_URL[ENV.STAGING], EPNS_COMMUNICATOR_CONTRACT: '0xb3971BCef2D791bc4027BbfedFb47319A4AAaaAa', }, + [BLOCKCHAIN_NETWORK.ARBITRUM_TESTNET]: { + API_BASE_URL: API_BASE_URL[ENV.STAGING], + EPNS_COMMUNICATOR_CONTRACT: '0xb3971BCef2D791bc4027BbfedFb47319A4AAaaAa', + }, }, [ENV.DEV]: { [BLOCKCHAIN_NETWORK.ETH_GOERLI]: { @@ -212,6 +228,10 @@ const CONFIG = { API_BASE_URL: API_BASE_URL[ENV.DEV], EPNS_COMMUNICATOR_CONTRACT: '0x630b152e4185c63D7177c656b56b26f878C61572', }, + [BLOCKCHAIN_NETWORK.ARBITRUM_TESTNET]: { + API_BASE_URL: API_BASE_URL[ENV.STAGING], + EPNS_COMMUNICATOR_CONTRACT: '0x2f6aE0907116A2c50D712e78b48D874fadeB6850', + }, }, [ENV.LOCAL]: { [BLOCKCHAIN_NETWORK.ETH_GOERLI]: { @@ -234,6 +254,10 @@ const CONFIG = { API_BASE_URL: API_BASE_URL[ENV.DEV], EPNS_COMMUNICATOR_CONTRACT: '0x630b152e4185c63D7177c656b56b26f878C61572', }, + [BLOCKCHAIN_NETWORK.ARBITRUM_TESTNET]: { + API_BASE_URL: API_BASE_URL[ENV.STAGING], + EPNS_COMMUNICATOR_CONTRACT: '0x2f6aE0907116A2c50D712e78b48D874fadeB6850', + }, }, }; diff --git a/packages/restapi/src/lib/constants.ts b/packages/restapi/src/lib/constants.ts index 4735b547a..94d46f3d4 100644 --- a/packages/restapi/src/lib/constants.ts +++ b/packages/restapi/src/lib/constants.ts @@ -27,21 +27,20 @@ export enum ENCRYPTION_TYPE { export enum MessageType { TEXT = 'Text', IMAGE = 'Image', + VIDEO = 'Video', + AUDIO = 'Audio', FILE = 'File', + /** @deprecated - Use `MediaEmbed` Instead */ + GIF = 'GIF', MEDIA_EMBED = 'MediaEmbed', META = 'Meta', REACTION = 'Reaction', - /** - * @deprecated - Use MediaEmbed Instead - */ - GIF = 'GIF', - - // TODO - // AUDIO = 'Audio', - // VIDEO = 'Video', - // PAYMENT = 'Payment', - // REPLY = 'Reply', - // COMPOSITE = 'Composite', + RECEIPT = 'Receipt', + USER_ACTIVITY = 'UserActivity', + INTENT = 'Intent', + REPLY = 'Reply', + COMPOSITE = 'Composite', + PAYMENT = 'Payment', } const Constants = { @@ -55,7 +54,7 @@ const Constants = { }, DEFAULT_CHAIN_ID: 5, DEV_CHAIN_ID: 99999, - NON_ETH_CHAINS: [137, 80001, 56, 97, 10, 420, 1442, 1101], + NON_ETH_CHAINS: [137, 80001, 56, 97, 10, 420, 1442, 1101, 421613, 42161], ETH_CHAINS: [1, 5], ENC_TYPE_V1: 'x25519-xsalsa20-poly1305', ENC_TYPE_V2: 'aes256GcmHkdfSha256', diff --git a/packages/restapi/src/lib/payloads/constants.ts b/packages/restapi/src/lib/payloads/constants.ts index a3c5d9a41..da01fafc7 100644 --- a/packages/restapi/src/lib/payloads/constants.ts +++ b/packages/restapi/src/lib/payloads/constants.ts @@ -13,6 +13,8 @@ export const CHAIN_ID_TO_SOURCE: ChainIdToSourceType = { 420: 'OPTIMISM_TESTNET', 1442: 'POLYGON_ZK_EVM_TESTNET', 1101: 'POLYGON_ZK_EVM_MAINNET', + 421613: "ARBITRUM_TESTNET", + 42161: "ARBITRUMONE_MAINNET" }; export const SOURCE_TYPES = { @@ -26,6 +28,8 @@ export const SOURCE_TYPES = { OPTIMISM_TESTNET: 'OPTIMISM_TESTNET', POLYGON_ZK_EVM_TESTNET: 'POLYGON_ZK_EVM_TESTNET', POLYGON_ZK_EVM_MAINNET: 'POLYGON_ZK_EVM_MAINNET', + ARBITRUM_TESTNET: "ARBITRUM_TESTNET", + ARBITRUMONE_MAINNET: "ARBITRUMONE_MAINNET", THE_GRAPH: 'THE_GRAPH', PUSH_VIDEO: 'PUSH_VIDEO', }; diff --git a/packages/restapi/src/lib/payloads/helpers.ts b/packages/restapi/src/lib/payloads/helpers.ts index 6b7016feb..1863ed1ca 100644 --- a/packages/restapi/src/lib/payloads/helpers.ts +++ b/packages/restapi/src/lib/payloads/helpers.ts @@ -321,7 +321,7 @@ export function getSource( export function getCAIPFormat(chainId: number, address: string) { // EVM based chains - if ([1, 5, 42, 137, 80001, 56, 97, 10, 420, 1442, 1101].includes(chainId)) { + if ([1, 5, 42, 137, 80001, 56, 97, 10, 420, 1442, 1101, 421613, 42161].includes(chainId)) { return `eip155:${chainId}:${address}`; } diff --git a/packages/restapi/src/lib/space/Space.ts b/packages/restapi/src/lib/space/Space.ts index 7ddd78b27..a466da5fb 100644 --- a/packages/restapi/src/lib/space/Space.ts +++ b/packages/restapi/src/lib/space/Space.ts @@ -29,7 +29,7 @@ import { } from '../types'; import { VIDEO_CALL_TYPE } from '../payloads/constants'; import sendLiveSpaceData from './helpers/sendLiveSpaceData'; -import { META_ACTION } from '../types/messageTypes'; +import { CHAT } from '../types/messageTypes'; import { broadcastRaisedHand } from './broadcastRaisedHand'; import { onReceiveMetaMessage } from './onReceiveMetaMessage'; import { onJoinListener } from './onJoinListener'; @@ -157,7 +157,7 @@ export class Space extends Video { env: this.env, spaceId: this.spaceSpecificData.spaceId, signer: this.signer, - action: META_ACTION.PROMOTE_TO_ADMIN, // TODO: Add a meta action for SPEAKER_JOINED + action: CHAT.META.GROUP.ADMIN.PRVILEGE, // TODO: Add a meta action for SPEAKER_JOINED }); } }, diff --git a/packages/restapi/src/lib/space/broadcastRaisedHand.ts b/packages/restapi/src/lib/space/broadcastRaisedHand.ts index db2c0b1c9..d90b706e8 100644 --- a/packages/restapi/src/lib/space/broadcastRaisedHand.ts +++ b/packages/restapi/src/lib/space/broadcastRaisedHand.ts @@ -1,6 +1,6 @@ import { produce } from 'immer'; import sendLiveSpaceData from './helpers/sendLiveSpaceData'; -import { META_ACTION } from '../types/messageTypes'; +import { CHAT } from '../types/messageTypes'; import { pCAIP10ToWallet } from '../helpers'; import type Space from './Space'; @@ -41,6 +41,6 @@ export async function broadcastRaisedHand( env: this.env, spaceId: this.spaceSpecificData.spaceId, signer: this.signer, - action: META_ACTION.USER_INTERACTION, + action: CHAT.META.GROUP.USER.INTERACTION, }); } diff --git a/packages/restapi/src/lib/space/helpers/getLiveSpaceData.ts b/packages/restapi/src/lib/space/helpers/getLiveSpaceData.ts index 4d3f952a4..7f8896b00 100644 --- a/packages/restapi/src/lib/space/helpers/getLiveSpaceData.ts +++ b/packages/restapi/src/lib/space/helpers/getLiveSpaceData.ts @@ -1,7 +1,7 @@ import { conversationHash, history } from '../../chat'; import { MessageType } from '../../constants'; import { EnvOptionsType, LiveSpaceData } from '../../types'; -import { MetaMessage } from '../../types/messageTypes'; +import { InfoMessage } from '../../types/messageTypes'; import { initLiveSpaceData } from '../Space'; interface GetLatestMessageType extends EnvOptionsType { @@ -54,7 +54,7 @@ const getLiveSpaceData = async ({ latestMetaMessage.messageObj !== null ) { // found the latest meta message - liveSpaceData = (latestMetaMessage.messageObj as Omit) + liveSpaceData = (latestMetaMessage.messageObj as Omit) ?.info?.arbitrary as LiveSpaceData; } diff --git a/packages/restapi/src/lib/space/helpers/sendLiveSpaceData.ts b/packages/restapi/src/lib/space/helpers/sendLiveSpaceData.ts index 78cb59fb1..099eed844 100644 --- a/packages/restapi/src/lib/space/helpers/sendLiveSpaceData.ts +++ b/packages/restapi/src/lib/space/helpers/sendLiveSpaceData.ts @@ -1,11 +1,10 @@ import { send } from '../../chat'; import { MessageType } from '../../constants'; import { EnvOptionsType, LiveSpaceData, SignerType } from '../../types'; -import { META_ACTION } from '../../types/messageTypes'; interface SendLiveSpaceData extends EnvOptionsType { liveSpaceData?: LiveSpaceData; - action: META_ACTION; + action: string; spaceId: string; pgpPrivateKey: string; signer: SignerType; @@ -26,8 +25,7 @@ const sendLiveSpaceData = async ({ signer, messageType: MessageType.META, messageObj: { - content: 'PUSH SPACE META MESSAGE', - action, + content: action, info: { affected: [], arbitrary: liveSpaceData, diff --git a/packages/restapi/src/lib/space/onJoinListener.ts b/packages/restapi/src/lib/space/onJoinListener.ts index 30db1c4dd..72aa30c68 100644 --- a/packages/restapi/src/lib/space/onJoinListener.ts +++ b/packages/restapi/src/lib/space/onJoinListener.ts @@ -3,7 +3,7 @@ import { get } from './get'; import { pCAIP10ToWallet } from '../helpers'; import { produce } from 'immer'; -import { META_ACTION } from '../types/messageTypes'; +import { CHAT } from '../types/messageTypes'; import type Space from './Space'; export interface OnJoinListenerType { @@ -43,11 +43,12 @@ export async function onJoinListener(this: Space, options: OnJoinListenerType) { const modifiedLiveSpaceData = produce( this.spaceSpecificData.liveSpaceData, (draft) => { - const isListenerAlreadyAdded = this.spaceSpecificData.liveSpaceData.listeners.find( - (currentListener) => - pCAIP10ToWallet(currentListener.address) === - pCAIP10ToWallet(receivedAddress) - ); + const isListenerAlreadyAdded = + this.spaceSpecificData.liveSpaceData.listeners.find( + (currentListener) => + pCAIP10ToWallet(currentListener.address) === + pCAIP10ToWallet(receivedAddress) + ); if (isListenerAlreadyAdded) { // listener is already added in the meta message @@ -75,6 +76,6 @@ export async function onJoinListener(this: Space, options: OnJoinListenerType) { env: this.env, signer: this.signer, liveSpaceData: modifiedLiveSpaceData, - action: META_ACTION.ADD_LISTENER, + action: CHAT.META.SPACE.LISTENER.ADD, }); } diff --git a/packages/restapi/src/lib/space/onReceiveMetaMessage.ts b/packages/restapi/src/lib/space/onReceiveMetaMessage.ts index f6b6ae24c..800511e31 100644 --- a/packages/restapi/src/lib/space/onReceiveMetaMessage.ts +++ b/packages/restapi/src/lib/space/onReceiveMetaMessage.ts @@ -1,6 +1,6 @@ import { MessageType } from '../constants'; import { IMessageIPFS, LiveSpaceData } from '../types'; -import { MetaMessage } from '../types/messageTypes'; +import { InfoMessage } from '../types/messageTypes'; import type Space from './Space'; export interface OnReceiveMetaMessageType { @@ -18,14 +18,14 @@ export function onReceiveMetaMessage( if ( receivedMetaMessage.messageType !== MessageType.META || typeof receivedMetaMessage.messageObj !== 'object' || - !(receivedMetaMessage?.messageObj as Omit)?.info + !(receivedMetaMessage?.messageObj as Omit)?.info ?.arbitrary ) { return; } const receivedLiveSpaceData = ( - receivedMetaMessage.messageObj as Omit + receivedMetaMessage.messageObj as Omit ).info.arbitrary as LiveSpaceData; console.log('RECEIVED LIVE SPACE DATA', receivedLiveSpaceData); diff --git a/packages/restapi/src/lib/space/rejectPromotionRequest.ts b/packages/restapi/src/lib/space/rejectPromotionRequest.ts index 3fb45154b..f2be499e9 100644 --- a/packages/restapi/src/lib/space/rejectPromotionRequest.ts +++ b/packages/restapi/src/lib/space/rejectPromotionRequest.ts @@ -1,6 +1,6 @@ import { produce } from 'immer'; import sendLiveSpaceData from './helpers/sendLiveSpaceData'; -import { META_ACTION } from '../types/messageTypes'; +import { CHAT } from '../types/messageTypes'; import { pCAIP10ToWallet } from '../helpers'; import type Space from './Space'; @@ -41,6 +41,6 @@ export async function rejectPromotionRequest( env: this.env, spaceId: this.spaceSpecificData.spaceId, signer: this.signer, - action: META_ACTION.USER_INTERACTION, // TODO: Add a reject request type + action: CHAT.META.GROUP.USER.INTERACTION, // TODO: Add a reject request type }); } diff --git a/packages/restapi/src/lib/space/start.ts b/packages/restapi/src/lib/space/start.ts index 6a14791e7..70c369a13 100644 --- a/packages/restapi/src/lib/space/start.ts +++ b/packages/restapi/src/lib/space/start.ts @@ -24,7 +24,7 @@ export interface StartSpaceType extends EnvOptionsType { import type Space from './Space'; import { produce } from 'immer'; import { pCAIP10ToWallet } from '../helpers'; -import { META_ACTION } from '../types/messageTypes'; +import { CHAT } from '../types/messageTypes'; import sendLiveSpaceData from './helpers/sendLiveSpaceData'; type StartType = { @@ -93,7 +93,7 @@ export async function start(this: Space, options: StartType): Promise { await sendLiveSpaceData({ liveSpaceData, - action: META_ACTION.CREATE_SPACE, + action: CHAT.META.SPACE.CREATE, spaceId: this.spaceSpecificData.spaceId, signer: this.signer, pgpPrivateKey: this.pgpPrivateKey, diff --git a/packages/restapi/src/lib/types/messageTypes.ts b/packages/restapi/src/lib/types/messageTypes.ts index 49f4d986a..634121784 100644 --- a/packages/restapi/src/lib/types/messageTypes.ts +++ b/packages/restapi/src/lib/types/messageTypes.ts @@ -3,67 +3,92 @@ */ import { MessageType } from '../constants'; -export enum META_ACTION { - /** - * DEFAULT GROUP ACTIONS - */ - CREATE_GROUP = 1, - ADD_MEMBER = 2, - REMOVE_MEMBER = 3, - PROMOTE_TO_ADMIN = 4, - DEMOTE_FROM_ADMIN = 5, - /** - * SHARED ACTIONS - */ - CHANGE_IMAGE_OR_DESC = 6, - CHANGE_META = 7, - /** - * SPACES ACTIONS - */ - CREATE_SPACE = 8, - ADD_LISTENER = 9, - REMOVE_LISTENER = 10, - PROMOTE_TO_SPEAKER = 11, - DEMOTE_FROM_SPEARKER = 12, - PROMOTE_TO_COHOST = 13, - DEMOTE_FROM_COHOST = 14, - USER_INTERACTION = 15, // For MIC_ON | MIC_OFF | RAISE_HAND | EMOJI REACTION | or any other user activity -} +export const CHAT = { + META: { + GROUP: { + CREATE: 'CREATE_GROUP', + MEMBER: { + ADD: 'ADD_MEMBER', + REMOVE: 'REMOVE_MEMBER', + PRIVILEGE: 'ASSIGN_MEMBER_PRIVILEGE', + }, + ADMIN: { + PRVILEGE: 'ASSIGN_ADMIN_PRIVILEGE', + }, + // todo: Why do we need update group when we already have profile and meta update + UPDATE: 'UPDATE_GROUP', + PROFILE: { + UPDATE: 'UPDATE_GROUP_PROFILE', + }, + // todo : this seems to be a wierd name CHAT.META.GROUP.META.UPDATE + META: { + UPDATE: 'UPDATE_GROUP_META', + }, + // todo : Remove this as it comes under UserActivity now ( remove after space changes ) + USER: { + INTERACTION: 'USER_INTERACTION', + }, + }, + SPACE: { + CREATE: 'CREATE_SPACE', + LISTENER: { + ADD: 'ADD_LISTENER', + REMOVE: 'REMOVE_LISTENER', + PRVILEGE: 'ASSIGN_LISTENER_PRIVILEGE', + }, + SPEAKER: { + PRVILEGE: 'ASSIGN_SPEAKER_PRIVILEGE', + }, + COHOST: { + PRVILEGE: 'ASSIGN_COHOST_PRIVILEGE', + }, + }, + }, -export enum REACTION_TYPE { - THUMBS_UP, - THUMBS_DOWN, - HEART, - CLAP, - LAUGHING_FACE, - SAD_FACE, - ANGRY_FACE, - SURPRISED_FACE, - CLAPPING_HANDS, - FIRE, -} + REACTION: { + THUMBSUP: '\u{1F44D}', + THUMBSDOWN: '\u{1F44E}', + HEART: '\u{2764}\u{FE0F}', + CLAP: '\u{1F44F}', + LAUGH: '\u{1F602}', + SAD: '\u{1F622}', + ANGRY: '\u{1F621}', + SUPRISE: '\u{1F632}', + FIRE: '\u{1F525}', + }, + + RECEIPT: { + READ: 'READ_RECEIPT', + }, -// Create a mapping object that associates reaction types with their Unicode escape sequences -export const REACTION_SYMBOL: Record = { - [REACTION_TYPE.THUMBS_UP]: '\u{1F44D}', - [REACTION_TYPE.THUMBS_DOWN]: '\u{1F44E}', - [REACTION_TYPE.HEART]: '\u{2764}\u{FE0F}', - [REACTION_TYPE.CLAP]: '\u{1F44F}', - [REACTION_TYPE.LAUGHING_FACE]: '\u{1F602}', - [REACTION_TYPE.SAD_FACE]: '\u{1F622}', - [REACTION_TYPE.ANGRY_FACE]: '\u{1F621}', - [REACTION_TYPE.SURPRISED_FACE]: '\u{1F632}', - [REACTION_TYPE.CLAPPING_HANDS]: '\u{1F44F}\u{1F44F}', - [REACTION_TYPE.FIRE]: '\u{1F525}', + UA: { + LISTENER: { + JOIN: 'LISTENER_JOIN', + LEAVE: 'LISTENER_LEAVE', + MICREQUEST: 'LISTENER_REQUEST_MIC', + }, + SPEAKER: { + MIC_ON: 'SPEAKER_MIC_ON', + MIC_OFF: 'SPEAKER_MIC_OFF', + }, + }, + + INTENT: { + ACCEPT: 'ACCEPT_INTENT', + REJECT: 'REJECT_INTENT', + JOIN: 'JOIN_GROUP', + LEAVE: 'LEAVE_GROUP', + }, }; -export interface BaseMessage { +interface BaseMessage { type?: T; content: string; } -export interface MetaMessage extends BaseMessage<`${MessageType.META}`> { - action: META_ACTION; +// Used by MessageType.Meta & MessageType.USER_ACTIVITY +export interface InfoMessage + extends BaseMessage<`${MessageType.META}` | `${MessageType.USER_ACTIVITY}`> { info: { affected: string[]; arbitrary?: { @@ -72,28 +97,53 @@ export interface MetaMessage extends BaseMessage<`${MessageType.META}`> { }; } -export interface ReactionMessage - extends BaseMessage<`${MessageType.REACTION}`> { - action: REACTION_TYPE; - reference?: string | null; +interface ReferenceMessage + extends BaseMessage<`${MessageType.REACTION}` | `${MessageType.RECEIPT}`> { + reference: string; +} + +interface ReplyMessage { + type: `${MessageType.REPLY}`; + /** Only Few BaseMessageTypes are allowed, this can be changed in the future */ + content: { + type: string; + content: string; + }; + reference: string; +} + +interface CompositeMessage { + type: `${MessageType.COMPOSITE}`; + /** Only Few BaseMessageTypes are allowed, this can be changed in the future */ + content: { + type: string; + content: string; + }[]; } -export type BaseMessageTypes = +type BaseMessageTypes = | `${MessageType.TEXT}` | `${MessageType.IMAGE}` + | `${MessageType.VIDEO}` + | `${MessageType.AUDIO}` | `${MessageType.FILE}` + | `${MessageType.GIF}` | `${MessageType.MEDIA_EMBED}` - | `${MessageType.GIF}`; + | `${MessageType.INTENT}`; export type Message = | BaseMessage - | MetaMessage - | ReactionMessage; + | InfoMessage + | ReferenceMessage + | ReplyMessage + | CompositeMessage; /** * @deprecated */ export type MessageObj = | Omit, 'type'> - | Omit - | Omit; + | Omit + | Omit + | Omit + | Omit; diff --git a/packages/restapi/src/lib/validations/messageObject.ts b/packages/restapi/src/lib/validations/messageObject.ts index 6057d12d5..d40382126 100644 --- a/packages/restapi/src/lib/validations/messageObject.ts +++ b/packages/restapi/src/lib/validations/messageObject.ts @@ -1,14 +1,26 @@ import * as Joi from 'joi'; -import { META_ACTION, REACTION_TYPE } from '../types/messageTypes'; +import { CHAT, MessageObj } from '../types/messageTypes'; +import { MessageType } from '../constants'; -export const messageObjSchema = Joi.object({ +const extractValidValues = (obj: any): string[] => { + const validValues: string[] = []; + for (const key in obj) { + if (typeof obj[key] === 'string') { + validValues.push(obj[key]); + } else if (typeof obj[key] === 'object') { + validValues.push(...extractValidValues(obj[key])); + } + } + return validValues; +}; + +const messageObjSchema = Joi.object({ content: Joi.string().required().allow(''), }); -export const metaMessageObjSchema = Joi.object({ - content: Joi.string().required().allow(''), - action: Joi.number() - .valid(...Object.values(META_ACTION)) +const metaMessageObjSchema = Joi.object({ + content: Joi.string() + .valid(...Object.values(extractValidValues(CHAT.META))) .required(), info: Joi.object({ affected: Joi.array().items(Joi.string()).required(), @@ -16,10 +28,133 @@ export const metaMessageObjSchema = Joi.object({ }).required(), }); -export const reationMessageObjSchema = Joi.object({ - content: Joi.string().required().allow(''), - action: Joi.number() - .valid(...Object.values(REACTION_TYPE)) +const reationMessageObjSchema = Joi.object({ + content: Joi.string() + .valid(...Object.values(extractValidValues(CHAT.REACTION))) + .required(), + reference: Joi.string().required(), +}); + +const receiptMessageObjSchema = Joi.object({ + content: Joi.string() + .valid(...Object.values(extractValidValues(CHAT.RECEIPT))) .required(), - reference: Joi.string().allow(null), + reference: Joi.string().required(), }); + +const userActivityMessageObjSchema = Joi.object({ + content: Joi.string() + .valid(...Object.values(extractValidValues(CHAT.UA))) + .required(), + info: Joi.object({ + affected: Joi.array().items(Joi.string()).required(), + arbitrary: Joi.object().pattern(Joi.string(), Joi.any()), + }).required(), +}); + +const intentMessageObjSchema = Joi.object({ + content: Joi.string().valid( + ...Object.values(extractValidValues(CHAT.INTENT)) + ), +}); + +const replyMessageObjSchema = Joi.object({ + content: Joi.object({ + messageType: Joi.string() + .valid( + ...Object.values([ + MessageType.TEXT, + MessageType.IMAGE, + MessageType.AUDIO, + MessageType.VIDEO, + MessageType.FILE, + MessageType.MEDIA_EMBED, + ]) + ) + .required(), + messageObj: Joi.object({ + content: Joi.string().required(), // Change the validation as needed + }).required(), + }).required(), + reference: Joi.string().required(), +}); + +const compositeMessageObjSchema = Joi.object({ + content: Joi.array() + .items( + Joi.object({ + messageType: Joi.string() + .valid( + ...Object.values([ + MessageType.TEXT, + MessageType.IMAGE, + MessageType.AUDIO, + MessageType.VIDEO, + MessageType.FILE, + MessageType.MEDIA_EMBED, + ]) + ) + .required(), + messageObj: Joi.object({ + content: Joi.string().required(), + }).required(), + }) + ) + .required(), +}); + +export const validateMessageObj = ( + messageObj: MessageObj, + messageType: MessageType +) => { + let error: Joi.ValidationError | undefined = undefined; + switch (messageType) { + case MessageType.TEXT: + case MessageType.IMAGE: + case MessageType.VIDEO: + case MessageType.AUDIO: + case MessageType.FILE: + case MessageType.MEDIA_EMBED: + case MessageType.GIF: { + error = messageObjSchema.validate(messageObj).error; + break; + } + case MessageType.META: { + error = metaMessageObjSchema.validate(messageObj).error; + break; + } + case MessageType.REACTION: { + error = reationMessageObjSchema.validate(messageObj).error; + break; + } + case MessageType.RECEIPT: { + error = receiptMessageObjSchema.validate(messageObj).error; + break; + } + case MessageType.USER_ACTIVITY: { + error = userActivityMessageObjSchema.validate(messageObj).error; + break; + } + case MessageType.INTENT: { + error = intentMessageObjSchema.validate(messageObj).error; + break; + } + case MessageType.REPLY: { + error = replyMessageObjSchema.validate(messageObj).error; + break; + } + case MessageType.COMPOSITE: { + error = compositeMessageObjSchema.validate(messageObj).error; + break; + } + default: { + throw new Error('Invalid MessageType'); + } + } + + if (error) { + throw new Error( + `Unable to parse this messageType. Please ensure 'messageObj' is properly defined.` + ); + } +}; diff --git a/packages/restapi/tests/lib/chat/createGroup.test.ts b/packages/restapi/tests/lib/chat/createGroup.test.ts index 5c8db3987..d9ea55a2e 100644 --- a/packages/restapi/tests/lib/chat/createGroup.test.ts +++ b/packages/restapi/tests/lib/chat/createGroup.test.ts @@ -127,8 +127,8 @@ const expectGroup = async ( expect(group.members[0].image).to.be.a('string'); expect(group.pendingMembers).to.be.an('array'); expect(group.pendingMembers.length).to.equal(pendingMembers.length); - expect(group.pendingMembers[0].wallet).to.equal(pendingMembers[0]); - expect(group.pendingMembers[1].wallet).to.equal(pendingMembers[1]); + expect(pendingMembers.includes(group.pendingMembers[0].wallet)).to.be.true; + expect(pendingMembers.includes(group.pendingMembers[1].wallet)).to.be.true; expect(group.groupImage).to.equal(groupImage); expect(group.groupName).to.equal(groupName); expect(group.groupDescription).to.equal(groupDescription); diff --git a/packages/restapi/tests/lib/chat/send.test.ts b/packages/restapi/tests/lib/chat/send.test.ts index fc3e8d0dd..5aeb21512 100644 --- a/packages/restapi/tests/lib/chat/send.test.ts +++ b/packages/restapi/tests/lib/chat/send.test.ts @@ -6,7 +6,7 @@ import { ethers } from 'ethers'; import Constants, { MessageType } from '../../../src/lib/constants'; import { upgrade } from '../../../src/lib/user/upgradeUser'; import { decryptPGPKey } from '../../../src/lib/helpers'; -import { createGroup, send } from '../../../src/lib/chat'; +import { approve, createGroup, send } from '../../../src/lib/chat'; import { MessageWithCID, SignerType } from '../../../src/lib/types'; import { decryptAndVerifyMessage } from '../../../src/lib/chat/helpers'; import { @@ -15,14 +15,11 @@ import { colors, uniqueNamesGenerator, } from 'unique-names-generator'; -import { - REACTION_SYMBOL, - REACTION_TYPE, -} from '../../../src/lib/types/messageTypes'; +import { CHAT } from '../../../src/lib/types/messageTypes'; chai.use(chaiAsPromised); const _env = Constants.ENV.DEV; -describe('PushAPI.chat.send', () => { +describe.only('PushAPI.chat.send', () => { const provider = ethers.getDefaultProvider(5); let _signer1: any; let walletAddress1: string; @@ -630,6 +627,232 @@ describe('PushAPI.chat.send', () => { ); }); }); + describe('Video Message', () => { + const MESSAGE_TYPE = MessageType.VIDEO; + const MESSAGE = '{"content":"data:application/mp4;base64,JVBERi0xLjQKJ}'; + it('should throw error using wrong messageObj', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + action: 1, + info: { affected: [] }, + }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + // Video message was not supported in v1 & v2 + it('should throw error for deprecated V1', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageContent: MESSAGE, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('Deprecated V2 | EncType - Plaintext', async () => { + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + MESSAGE, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('Deprecated V2 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + version: Constants.ENC_TYPE_V1, + }); + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + MESSAGE, + account1, + _signer1, + account2, + 'pgp' + ); + }); + it('V3 | EncType - Plaintext', async () => { + const msg = await send({ + message: { type: MESSAGE_TYPE, content: MESSAGE }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { content: MESSAGE }, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('V3 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + version: Constants.ENC_TYPE_V1, + }); + const msg = await send({ + message: { type: MESSAGE_TYPE, content: MESSAGE }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { content: MESSAGE }, + account1, + _signer1, + account2, + 'pgp' + ); + }); + }); + describe('Audio Message', () => { + const MESSAGE_TYPE = MessageType.AUDIO; + const MESSAGE = '{"content":"data:application/mp3;base64,JVBERi0xLjQKJ}'; + it('should throw error using wrong messageObj', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + action: 1, + info: { affected: [] }, + }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + // Audio message was not supported in v1 & v2 + it('should throw error for deprecated V1', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageContent: MESSAGE, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('Deprecated V2 | EncType - Plaintext', async () => { + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + MESSAGE, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('Deprecated V2 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + version: Constants.ENC_TYPE_V1, + }); + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + MESSAGE, + account1, + _signer1, + account2, + 'pgp' + ); + }); + it('V3 | EncType - Plaintext', async () => { + const msg = await send({ + message: { type: MESSAGE_TYPE, content: MESSAGE }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { content: MESSAGE }, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('V3 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + version: Constants.ENC_TYPE_V1, + }); + const msg = await send({ + message: { type: MESSAGE_TYPE, content: MESSAGE }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { content: MESSAGE }, + account1, + _signer1, + account2, + 'pgp' + ); + }); + }); describe('File Message', () => { const MESSAGE_TYPE = MessageType.FILE; const MESSAGE = '{"content":"data:application/pdf;base64,JVBERi0xLjQKJ}'; @@ -773,8 +996,8 @@ describe('PushAPI.chat.send', () => { ); }); }); - describe('MediaEmbed Message', () => { - const MESSAGE_TYPE = MessageType.MEDIA_EMBED; + describe('GIF Message', () => { + const MESSAGE_TYPE = MessageType.GIF; const MESSAGE = 'ttps://media1.giphy.com/media/FtlUfrq3pVZXVNjoxf/giphy360p.mp4?cid=ecf05e47jk317254v9hbdjrknemduocie4pf54wtsir98xsx&ep=v1_videos_search&rid=giphy360p.mp4&ct=v'; it('should throw error using wrong messageObj', async () => { @@ -917,8 +1140,8 @@ describe('PushAPI.chat.send', () => { ); }); }); - describe('GIF Message', () => { - const MESSAGE_TYPE = MessageType.GIF; + describe('MediaEmbed Message', () => { + const MESSAGE_TYPE = MessageType.MEDIA_EMBED; const MESSAGE = 'ttps://media1.giphy.com/media/FtlUfrq3pVZXVNjoxf/giphy360p.mp4?cid=ecf05e47jk317254v9hbdjrknemduocie4pf54wtsir98xsx&ep=v1_videos_search&rid=giphy360p.mp4&ct=v'; it('should throw error using wrong messageObj', async () => { @@ -1063,7 +1286,7 @@ describe('PushAPI.chat.send', () => { }); describe('Meta Message', () => { const MESSAGE_TYPE = MessageType.META; - const MESSAGE = 'xyz created group PUSH'; + const MESSAGE = CHAT.META.GROUP.CREATE; it('should throw error using messageContent or wrong MessageObject', async () => { await expect( send({ @@ -1087,7 +1310,7 @@ describe('PushAPI.chat.send', () => { await expect( send({ messageType: MESSAGE_TYPE, - messageObj: { content: MESSAGE, reference: '' }, + messageObj: { content: MESSAGE }, messageContent: MESSAGE, receiverAddress: account2, signer: _signer1, @@ -1097,30 +1320,25 @@ describe('PushAPI.chat.send', () => { await expect( send({ messageType: MESSAGE_TYPE, - messageObj: { content: MESSAGE, action: 1 }, // no info provided + messageObj: { content: MESSAGE, action: 1 }, // no info messageContent: MESSAGE, receiverAddress: account2, signer: _signer1, env: _env, }) ).to.be.rejected; - }); - it('should throw error for non-group', async () => { await expect( send({ messageType: MESSAGE_TYPE, - messageObj: { - content: MESSAGE, - action: 1, - info: { affected: [] }, - }, + messageObj: { content: MESSAGE, action: 1, info: { affected: [] } }, // action is not allowed + messageContent: MESSAGE, receiverAddress: account2, signer: _signer1, env: _env, }) ).to.be.rejected; }); - it('should throw error for non member of group', async () => { + it('should throw error for invalid content', async () => { const groupName = uniqueNamesGenerator({ dictionaries: [adjectives, colors, animals], }); @@ -1133,28 +1351,76 @@ describe('PushAPI.chat.send', () => { const group = await createGroup({ groupName, groupDescription, - members: [_nftAccount1, _nftAccount2], + members: [_nftAccount1, _nftAccount2, account2], groupImage, admins: [], // takes signer as admin automatically, add more if you want to isPublic: true, signer: _signer1, env: _env, }); + + await expect( + send({ + messageType: MESSAGE_TYPE, + message: { + type: MESSAGE_TYPE, + content: 'INVALID CONTENT', + info: { affected: [] }, + }, + receiverAddress: group.chatId, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error for non-group', async () => { await expect( send({ messageType: MESSAGE_TYPE, messageObj: { content: MESSAGE, - action: 1, info: { affected: [] }, }, - receiverAddress: group.chatId, - signer: _signer2, + receiverAddress: account2, + signer: _signer1, env: _env, }) ).to.be.rejected; }); - it('should throw error for Non-Admin member of group', async () => { + it('should throw error for non member of group', async () => { + const groupName = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupDescription = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupImage = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg=='; + + const group = await createGroup({ + groupName, + groupDescription, + members: [_nftAccount1, _nftAccount2], + groupImage, + admins: [], // takes signer as admin automatically, add more if you want to + isPublic: true, + signer: _signer1, + env: _env, + }); + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + info: { affected: [] }, + }, + receiverAddress: group.chatId, + signer: _signer2, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error for Non-Admin member of group', async () => { const groupName = uniqueNamesGenerator({ dictionaries: [adjectives, colors, animals], }); @@ -1179,7 +1445,6 @@ describe('PushAPI.chat.send', () => { messageType: MESSAGE_TYPE, messageObj: { content: MESSAGE, - action: 1, info: { affected: [] }, }, receiverAddress: group.chatId, @@ -1212,7 +1477,6 @@ describe('PushAPI.chat.send', () => { messageType: MESSAGE_TYPE, messageObj: { content: MESSAGE, - action: 1, info: { affected: [] }, }, receiverAddress: group.chatId, @@ -1222,7 +1486,7 @@ describe('PushAPI.chat.send', () => { await expectMsg( msg, MESSAGE_TYPE, - { content: MESSAGE, action: 1, info: { affected: [] } }, + { content: MESSAGE, info: { affected: [] } }, account1, _signer1, group.chatId, @@ -1253,7 +1517,6 @@ describe('PushAPI.chat.send', () => { messageType: MESSAGE_TYPE, messageObj: { content: MESSAGE, - action: 1, info: { affected: [] }, }, receiverAddress: group.chatId, @@ -1263,7 +1526,7 @@ describe('PushAPI.chat.send', () => { await expectMsg( msg, MESSAGE_TYPE, - { content: MESSAGE, action: 1, info: { affected: [] } }, + { content: MESSAGE, info: { affected: [] } }, account1, _signer1, group.chatId, @@ -1294,7 +1557,6 @@ describe('PushAPI.chat.send', () => { message: { type: MESSAGE_TYPE, content: MESSAGE, - action: 1, info: { affected: [] }, }, to: group.chatId, @@ -1304,7 +1566,7 @@ describe('PushAPI.chat.send', () => { await expectMsg( msg, MESSAGE_TYPE, - { content: MESSAGE, action: 1, info: { affected: [] } }, + { content: MESSAGE, info: { affected: [] } }, account1, _signer1, group.chatId, @@ -1335,7 +1597,6 @@ describe('PushAPI.chat.send', () => { message: { type: MESSAGE_TYPE, content: MESSAGE, - action: 1, info: { affected: [] }, }, to: group.chatId, @@ -1345,7 +1606,7 @@ describe('PushAPI.chat.send', () => { await expectMsg( msg, MESSAGE_TYPE, - { content: MESSAGE, action: 1, info: { affected: [] } }, + { content: MESSAGE, info: { affected: [] } }, account1, _signer1, group.chatId, @@ -1355,8 +1616,8 @@ describe('PushAPI.chat.send', () => { }); describe('Reaction Message', () => { const MESSAGE_TYPE = MessageType.REACTION; - const MESSAGE = ''; - it('should throw error using messageContent or wrong MessageObject', async () => { + const MESSAGE = CHAT.REACTION.CLAP; + it('should throw error using messageContent on wrong MessageObject', async () => { await expect( send({ messageType: MESSAGE_TYPE, @@ -1370,12 +1631,175 @@ describe('PushAPI.chat.send', () => { send({ messageType: MESSAGE_TYPE, messageObj: { content: MESSAGE }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE, info: { affected: [] } }, + messageContent: MESSAGE, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error on wrong content', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: 'Invalid Symbol', + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + messageContent: MESSAGE, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('Deprecated V1 | EncType - PlainText', async () => { + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: MESSAGE, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('Deprecated V1 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + }); + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: MESSAGE, // REACTION OVERRIDES THE MESSAGE CONTENT TO THE SYMBOL + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + account1, + _signer1, + account2, + 'pgp' + ); + }); + it('V2 | EncType - PlainText', async () => { + const msg = await send({ + message: { + type: MESSAGE_TYPE, + content: MESSAGE, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: MESSAGE, // REACTION OVERRIDES THE MESSAGE CONTENT TO THE SYMBOL, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('V2 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + }); + const msg = await send({ + message: { + type: MESSAGE_TYPE, + content: MESSAGE, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: MESSAGE, // REACTION OVERRIDES THE MESSAGE CONTENT TO THE SYMBOL + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + account1, + _signer1, + account2, + 'pgp' + ); + }); + }); + describe('Receipt Message', () => { + const MESSAGE_TYPE = MessageType.RECEIPT; + const MESSAGE = CHAT.RECEIPT.READ; + it('should throw error using messageContent on wrong MessageObject', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, messageContent: MESSAGE, receiverAddress: account2, signer: _signer1, env: _env, }) ).to.be.rejected; + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; await expect( send({ messageType: MESSAGE_TYPE, @@ -1387,12 +1811,29 @@ describe('PushAPI.chat.send', () => { }) ).to.be.rejected; }); + it('should throw error on wrong content', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: 'Invalid Message Content', + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + messageContent: MESSAGE, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); it('Deprecated V1 | EncType - PlainText', async () => { const msg = await send({ messageType: MESSAGE_TYPE, messageObj: { content: MESSAGE, - action: REACTION_TYPE.THUMBS_UP, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', }, receiverAddress: walletAddress2, signer: _signer1, @@ -1402,8 +1843,9 @@ describe('PushAPI.chat.send', () => { msg, MESSAGE_TYPE, { - content: REACTION_SYMBOL[REACTION_TYPE.THUMBS_UP], // REACTION OVERRIDES THE MESSAGE CONTENT TO THE SYMBOL, - action: REACTION_TYPE.THUMBS_UP, + content: MESSAGE, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', }, account1, _signer1, @@ -1421,7 +1863,8 @@ describe('PushAPI.chat.send', () => { messageType: MESSAGE_TYPE, messageObj: { content: MESSAGE, - action: REACTION_TYPE.THUMBS_UP, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', }, receiverAddress: walletAddress2, signer: _signer1, @@ -1431,8 +1874,9 @@ describe('PushAPI.chat.send', () => { msg, MESSAGE_TYPE, { - content: REACTION_SYMBOL[REACTION_TYPE.THUMBS_UP], // REACTION OVERRIDES THE MESSAGE CONTENT TO THE SYMBOL - action: REACTION_TYPE.THUMBS_UP, + content: MESSAGE, // REACTION OVERRIDES THE MESSAGE CONTENT TO THE SYMBOL + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', }, account1, _signer1, @@ -1445,7 +1889,8 @@ describe('PushAPI.chat.send', () => { message: { type: MESSAGE_TYPE, content: MESSAGE, - action: REACTION_TYPE.THUMBS_UP, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', }, to: walletAddress2, signer: _signer1, @@ -1455,8 +1900,9 @@ describe('PushAPI.chat.send', () => { msg, MESSAGE_TYPE, { - content: REACTION_SYMBOL[REACTION_TYPE.THUMBS_UP], // REACTION OVERRIDES THE MESSAGE CONTENT TO THE SYMBOL, - action: REACTION_TYPE.THUMBS_UP, + content: MESSAGE, // REACTION OVERRIDES THE MESSAGE CONTENT TO THE SYMBOL, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', }, account1, _signer1, @@ -1474,7 +1920,8 @@ describe('PushAPI.chat.send', () => { message: { type: MESSAGE_TYPE, content: MESSAGE, - action: REACTION_TYPE.THUMBS_UP, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', }, to: walletAddress2, signer: _signer1, @@ -1484,8 +1931,9 @@ describe('PushAPI.chat.send', () => { msg, MESSAGE_TYPE, { - content: REACTION_SYMBOL[REACTION_TYPE.THUMBS_UP], // REACTION OVERRIDES THE MESSAGE CONTENT TO THE SYMBOL - action: REACTION_TYPE.THUMBS_UP, + content: MESSAGE, // REACTION OVERRIDES THE MESSAGE CONTENT TO THE SYMBOL + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', }, account1, _signer1, @@ -1494,21 +1942,817 @@ describe('PushAPI.chat.send', () => { ); }); }); -}); + describe('User Activity Message', () => { + const MESSAGE_TYPE = MessageType.USER_ACTIVITY; + const MESSAGE = CHAT.UA.LISTENER.JOIN; + it('should throw error using messageContent or wrong MessageObject', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageContent: MESSAGE, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE }, + messageContent: MESSAGE, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE }, + messageContent: MESSAGE, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE, action: 1 }, // no info + messageContent: MESSAGE, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE, action: 1, info: { affected: [] } }, // action is not allowed + messageContent: MESSAGE, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error for invalid content', async () => { + const groupName = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupDescription = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupImage = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg=='; -/** - * HELPER FUNCTION - */ -const expectMsg = async ( - msg: MessageWithCID, - messageType: string, - content: string | { [key: string]: any }, - sender: string, - senderSigner: SignerType, // or receiverSigner - receiver: string, - encType?: 'PlainText' | 'pgp' -): Promise => { - expect(msg.fromDID).to.include(sender); + const group = await createGroup({ + groupName, + groupDescription, + members: [_nftAccount1, _nftAccount2, account2], + groupImage, + admins: [], // takes signer as admin automatically, add more if you want to + isPublic: true, + signer: _signer1, + env: _env, + }); + + await expect( + send({ + messageType: MESSAGE_TYPE, + message: { + type: MESSAGE_TYPE, + content: 'INVALID CONTENT', + info: { affected: [] }, + }, + receiverAddress: group.chatId, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error for non-group', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + info: { affected: [] }, + }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error for non member of group', async () => { + const groupName = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupDescription = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupImage = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg=='; + + const group = await createGroup({ + groupName, + groupDescription, + members: [_nftAccount1, _nftAccount2], + groupImage, + admins: [], // takes signer as admin automatically, add more if you want to + isPublic: true, + signer: _signer1, + env: _env, + }); + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + info: { affected: [] }, + }, + receiverAddress: group.chatId, + signer: _signer2, + env: _env, + }) + ).to.be.rejected; + }); + it('Deprecated V1 | EncType - PlainText ( Public Grp )', async () => { + const groupName = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupDescription = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupImage = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg=='; + + const group = await createGroup({ + groupName, + groupDescription, + members: [account2], + groupImage, + admins: [], // takes signer as admin automatically, add more if you want to + isPublic: true, + signer: _signer1, + env: _env, + }); + // approve intent + await approve({ + senderAddress: group.chatId, + status: 'Approved', + account: account2, + signer: _signer2, + env: _env, + }); + // send message + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + info: { affected: [] }, + }, + receiverAddress: group.chatId, + signer: _signer2, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { content: MESSAGE, info: { affected: [] } }, + account2, + _signer2, + group.chatId, + 'PlainText' + ); + }); + it('Deprecated V1 | EncType - pgp ( Private Grp )', async () => { + const groupName = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupDescription = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupImage = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg=='; + + const group = await createGroup({ + groupName, + groupDescription, + members: [_nftAccount1, _nftAccount2, account2], + groupImage, + admins: [], // takes signer as admin automatically, add more if you want to + isPublic: false, + signer: _signer1, + env: _env, + }); + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + info: { affected: [] }, + }, + receiverAddress: group.chatId, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { content: MESSAGE, info: { affected: [] } }, + account1, + _signer1, + group.chatId, + 'pgp' + ); + }); + it('V2 | EncType - PlainText ( Public Grp )', async () => { + const groupName = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupDescription = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupImage = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg=='; + + const group = await createGroup({ + groupName, + groupDescription, + members: [_nftAccount1, _nftAccount2, account2], + groupImage, + admins: [], // takes signer as admin automatically, add more if you want to + isPublic: true, + signer: _signer1, + env: _env, + }); + const msg = await send({ + message: { + type: MESSAGE_TYPE, + content: MESSAGE, + info: { affected: [] }, + }, + to: group.chatId, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { content: MESSAGE, info: { affected: [] } }, + account1, + _signer1, + group.chatId, + 'PlainText' + ); + }); + it('V2 | EncType - pgp ( Private Grp )', async () => { + const groupName = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupDescription = uniqueNamesGenerator({ + dictionaries: [adjectives, colors, animals], + }); + const groupImage = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAvklEQVR4AcXBsW2FMBiF0Y8r3GQb6jeBxRauYRpo4yGQkMd4A7kg7Z/GUfSKe8703fKDkTATZsJsrr0RlZSJ9r4RLayMvLmJjnQS1d6IhJkwE2bT13U/DBzp5BN73xgRZsJMmM1HOolqb/yWiWpvjJSUiRZWopIykTATZsJs5g+1N6KSMiO1N/5DmAkzYTa9Lh6MhJkwE2ZzSZlo7xvRwson3txERzqJhJkwE2bT6+JhoKTMJ2pvjAgzYSbMfgDlXixqjH6gRgAAAABJRU5ErkJggg=='; + + const group = await createGroup({ + groupName, + groupDescription, + members: [_nftAccount1, _nftAccount2, account2], + groupImage, + admins: [], // takes signer as admin automatically, add more if you want to + isPublic: false, + signer: _signer1, + env: _env, + }); + const msg = await send({ + message: { + type: MESSAGE_TYPE, + content: MESSAGE, + info: { affected: [] }, + }, + to: group.chatId, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { content: MESSAGE, info: { affected: [] } }, + account1, + _signer1, + group.chatId, + 'pgp' + ); + }); + }); + describe('Intent Message', () => { + const MESSAGE_TYPE = MessageType.INTENT; + const MESSAGE = CHAT.INTENT.ACCEPT; + it('should throw error using wrong messageObj', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + info: { affected: [] }, // not supported for intent + }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error using wrong content', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: 'Invalid Message', + }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('Deprecated V1 | EncType - Plaintext', async () => { + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + MESSAGE, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('Deprecated V1 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + version: Constants.ENC_TYPE_V1, + }); + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { content: MESSAGE }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + MESSAGE, + account1, + _signer1, + account2, + 'pgp' + ); + }); + it('V2 | EncType - Plaintext', async () => { + const msg = await send({ + message: { type: MESSAGE_TYPE, content: MESSAGE }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { content: MESSAGE }, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('V2 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + version: Constants.ENC_TYPE_V1, + }); + const msg = await send({ + message: { type: MESSAGE_TYPE, content: MESSAGE }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { content: MESSAGE }, + account1, + _signer1, + account2, + 'pgp' + ); + }); + }); + describe('Reply Message', () => { + const MESSAGE_TYPE = MessageType.REPLY; + const MESSAGE = { + type: MessageType.TEXT, + content: 'Replying to prev message', + }; + it('should throw error using wrong messageObj', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + // Adding content is legacy format is not allowed for reply + content: { + messageType: MessageType.TEXT, + messageObj: { + content: 'Hey', + }, + }, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error using wrong content', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: 'Invalid Message', + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error for unsupported messageType reply', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: { + type: MessageType.RECEIPT, + content: CHAT.RECEIPT.READ, + }, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('Deprecated V1 | EncType - Plaintext', async () => { + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: { + messageType: MESSAGE.type, + messageObj: { content: MESSAGE.content }, + }, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('Deprecated V1 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + version: Constants.ENC_TYPE_V1, + }); + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: { + messageType: MESSAGE.type, + messageObj: { content: MESSAGE.content }, + }, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + account1, + _signer1, + account2, + 'pgp' + ); + }); + it('V2 | EncType - Plaintext', async () => { + const msg = await send({ + message: { + type: MESSAGE_TYPE, + content: MESSAGE, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: { + messageType: MESSAGE.type, + messageObj: { content: MESSAGE.content }, + }, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('V2 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + version: Constants.ENC_TYPE_V1, + }); + const msg = await send({ + message: { + type: MESSAGE_TYPE, + content: MESSAGE, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: { + messageType: MESSAGE.type, + messageObj: { content: MESSAGE.content }, + }, + reference: + 'bafyreia22girudospfbs3q7t6eelb453rmwsi7shkejwxtwpp57xww6vae', + }, + account1, + _signer1, + account2, + 'pgp' + ); + }); + }); + describe('Composite Message', () => { + const MESSAGE_TYPE = MessageType.COMPOSITE; + const MESSAGE = [ + { + type: MessageType.TEXT as string, + content: 'Replying to prev message', + }, + ]; + it('should throw error using wrong messageObj', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + info: { affected: [] }, // not supported for composite + }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error using wrong content', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: 'Invalid Message', + }, + receiverAddress: account2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('should throw error for unsupported messageType composite', async () => { + await expect( + send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: [ + { + type: MessageType.READ_RECEIPT, + content: CHAT.READ_RECEIPT, + }, + ], + }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }) + ).to.be.rejected; + }); + it('Deprecated V1 | EncType - Plaintext', async () => { + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: [ + { + messageType: MESSAGE[0].type, + messageObj: { content: MESSAGE[0].content }, + }, + ], + }, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('Deprecated V1 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + version: Constants.ENC_TYPE_V1, + }); + const msg = await send({ + messageType: MESSAGE_TYPE, + messageObj: { + content: MESSAGE, + }, + receiverAddress: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: [ + { + messageType: MESSAGE[0].type, + messageObj: { content: MESSAGE[0].content }, + }, + ], + }, + account1, + _signer1, + account2, + 'pgp' + ); + }); + it('V2 | EncType - Plaintext', async () => { + const msg = await send({ + message: { + type: MESSAGE_TYPE, + content: MESSAGE, + }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: [ + { + messageType: MESSAGE[0].type, + messageObj: { content: MESSAGE[0].content }, + }, + ], + }, + account1, + _signer1, + account2, + 'PlainText' + ); + }); + it('V2 | EncType - pgp', async () => { + await create({ + account: account2, + env: _env, + signer: _signer2, + version: Constants.ENC_TYPE_V1, + }); + const msg = await send({ + message: { + type: MESSAGE_TYPE, + content: MESSAGE, + }, + to: walletAddress2, + signer: _signer1, + env: _env, + }); + await expectMsg( + msg, + MESSAGE_TYPE, + { + content: [ + { + messageType: MESSAGE[0].type, + messageObj: { content: MESSAGE[0].content }, + }, + ], + }, + account1, + _signer1, + account2, + 'pgp' + ); + }); + }); +}); + +/** + * HELPER FUNCTION + */ +const expectMsg = async ( + msg: MessageWithCID, + messageType: string, + content: string | { [key: string]: any }, + sender: string, + senderSigner: SignerType, // or receiverSigner + receiver: string, + encType?: 'PlainText' | 'pgp' +): Promise => { + expect(msg.fromDID).to.include(sender); expect(msg.fromCAIP10).to.include(sender); expect(msg.toDID).to.include(receiver); expect(msg.toCAIP10).to.include(receiver); @@ -1518,6 +2762,9 @@ const expectMsg = async ( expect(msg.sigType).to.equal(msg.verificationProof?.split(':')[0]); //Backward Compatibility check ( signature signs messageContent and will be diff from vProof ) expect(msg.signature).not.to.equal(msg.verificationProof?.split(':')[1]); + + const unsupportedContent = + 'MessageType Not Supported by this sdk version. Plz upgrade !!!'; try { if (encType && encType === 'pgp') { throw new Error('Should be encrypted'); @@ -1527,11 +2774,14 @@ const expectMsg = async ( if (typeof content === 'string') { expect((msg.messageObj as { content: string }).content).to.equal(content); //Backward Compatibility check - expect(msg.messageContent).to.equal(content); + expect(msg.messageContent).to.be.oneOf([content, unsupportedContent]); } else { expect(msg.messageObj).to.eql(content); //Backward Compatibility check - expect(msg.messageContent).to.equal((content as any).content); + expect(msg.messageContent).to.be.oneOf([ + (content as any).content, + unsupportedContent, + ]); } } catch (err) { if (encType && encType === 'PlainText') { @@ -1557,11 +2807,17 @@ const expectMsg = async ( content ); //Backward Compatibility check - expect(decryptedMsg.messageContent).to.equal(content); + expect(decryptedMsg.messageContent).to.be.oneOf([ + content, + unsupportedContent, + ]); } else { expect(decryptedMsg.messageObj).to.eql(content); //Backward Compatibility check - expect(decryptedMsg.messageContent).to.equal((content as any).content); + expect(decryptedMsg.messageContent).to.be.oneOf([ + (content as any).content, + unsupportedContent, + ]); } } }; diff --git a/packages/restapi/tests/lib/chat/updateGroup.test.ts b/packages/restapi/tests/lib/chat/updateGroup.test.ts index 436c10bd6..5f10b2db5 100644 --- a/packages/restapi/tests/lib/chat/updateGroup.test.ts +++ b/packages/restapi/tests/lib/chat/updateGroup.test.ts @@ -179,7 +179,7 @@ const expectGroup = async ( expect(group.pendingMembers).to.be.an('array'); expect(group.pendingMembers.length).to.equal(pendingMembers.length); for (let i = 0; i < pendingMembers.length; i++) { - expect(group.pendingMembers[i].wallet).to.equal(pendingMembers[i]); + expect(pendingMembers.includes(group.pendingMembers[i].wallet)).to.be.true; } expect(group.groupImage).to.equal(groupImage); expect(group.groupName).to.equal(groupName); diff --git a/packages/restapi/tests/lib/progressHook/progressHook.test.ts b/packages/restapi/tests/lib/progressHook/progressHook.test.ts index 3d177985b..4ea5a4155 100644 --- a/packages/restapi/tests/lib/progressHook/progressHook.test.ts +++ b/packages/restapi/tests/lib/progressHook/progressHook.test.ts @@ -86,14 +86,7 @@ describe('ProgressHook Tests', () => { for (let i = 0; i < progressInfo.length - 1; i++) { expect(progressInfo[i]).to.deep.equal(expectedHooks[i]); } - const expectedErrorHook = { - progressId: 'PUSH-ERROR-00', - progressTitle: 'Non Specific Error', - progressInfo: - '[Push SDK] - API - Error - API create() -: Error: [Push SDK] - API https://backend-dev.epns.io/apis/v2/users/: AxiosError: Request failed with status code 400', - level: 'ERROR', - }; - expect(progressInfo[4]).to.deep.equal(expectedErrorHook); + expect(progressInfo[4].progressId).to.be.equal('PUSH-ERROR-00'); } }); it('Decrypt Push Profile Success ProgressHooks', async () => { diff --git a/packages/uiweb/README.md b/packages/uiweb/README.md index fe84d77d5..d5f2e96f0 100644 --- a/packages/uiweb/README.md +++ b/packages/uiweb/README.md @@ -149,7 +149,7 @@ where | cta | string | Call To Action Link (given during notification creation) | | image | string | Any media link (given during notification creation) | | url | string | Channel Link (given during channel setup) | -| chainName | string | Can be anyone of the following blockchain networks on which the notification was sent - "ETH_MAINNET", "ETH_TEST_GOERLI", "POLYGON_MAINNET", "POLYGON_TEST_MUMBAI", "BSC_MAINNET, "BSC_TESTNET", "OPTIMISM_MAINNET", "OPTIMISM_TESTNET", "POLYGON_ZK_EVM_TESTNET", "POLYGON_ZK_EVM_MAINNET", "THE_GRAPH" | +| chainName | string | Can be anyone of the following blockchain networks on which the notification was sent - "ETH_MAINNET", "ETH_TEST_GOERLI", "POLYGON_MAINNET", "POLYGON_TEST_MUMBAI", "BSC_MAINNET, "BSC_TESTNET", "OPTIMISM_MAINNET", "OPTIMISM_TESTNET", "POLYGON_ZK_EVM_TESTNET", "POLYGON_ZK_EVM_MAINNET", "ARBITRUM_TESTNET", "ARBITRUMONE_MAINNET", "THE_GRAPH" | | theme | string | 'light' or 'dark' (customization to be given by the dApp) | | customTheme | INotificationItemTheme | custom theme object for the component | | isSpam | boolean | whether a spam notification or not | diff --git a/packages/uiweb/src/lib/components/chat/ConnectButton/ConnectButton.tsx b/packages/uiweb/src/lib/components/chat/ConnectButton/ConnectButton.tsx index 3b9f8c92c..b0090d41a 100644 --- a/packages/uiweb/src/lib/components/chat/ConnectButton/ConnectButton.tsx +++ b/packages/uiweb/src/lib/components/chat/ConnectButton/ConnectButton.tsx @@ -131,4 +131,4 @@ const ConnectButtonDiv = styled.div` body.modal-open { overflow-y: hidden; } -`; +`; \ No newline at end of file diff --git a/packages/uiweb/src/lib/components/chat/CreateGroup/AddCriteria.tsx b/packages/uiweb/src/lib/components/chat/CreateGroup/AddCriteria.tsx index d6893d8ea..8657a7084 100644 --- a/packages/uiweb/src/lib/components/chat/CreateGroup/AddCriteria.tsx +++ b/packages/uiweb/src/lib/components/chat/CreateGroup/AddCriteria.tsx @@ -1,5 +1,4 @@ -import React, { useContext, useState } from 'react'; - +import { useContext, useEffect, useState } from 'react'; import { Button, DropDownInput, @@ -7,7 +6,7 @@ import { ModalHeader, TextInput, } from '../reusables'; -import { Section, Span } from '../../reusables'; +import { Section, } from '../../reusables'; import EthereumSvg from '../../../icons/ethereum.svg'; import PolygonSvg from '../../../icons/polygon.svg'; import BSCSvg from '../../../icons/bsc.svg'; @@ -19,7 +18,6 @@ import { BLOCKCHAIN_NETWORK, device } from '../../../config'; import { GatingRulesInformation, ModalHeaderProps } from './CreateGroupModal'; import { useChatData } from '../../../hooks'; import { QuantityInput } from '../reusables/QuantityInput'; -import styled from 'styled-components'; import { ThemeContext } from '../theme/ThemeProvider'; import { Checkbox } from '../reusables/Checkbox'; import OptionButtons from '../reusables/OptionButtons'; @@ -34,11 +32,12 @@ import { TypeKeys, ReadonlyInputType, } from '../types'; +import { Data, GuildData, PushData, Rule } from '../types/tokenGatedGroupCreationType'; const AddCriteria = ({ handlePrevious, - //handle add criteria + entryCriteria, handleNext, onClose, }: ModalHeaderProps) => { @@ -246,8 +245,6 @@ const AddCriteria = ({ return false; }; - console.log(checkIfPushInvite()); - const getSubCategoryDropdownValues = () => { const category = getCategoryDropdownValues(); console.log(category); @@ -265,6 +262,118 @@ const AddCriteria = ({ setQuantity({ ...quantity, value: e.target.value }); }; + const verifyAndDoNext = ()=>{ + const _type = dropdownTypeValues[selectedTypeValue].value as 'PUSH' | 'GUILD' + const category:string = _type === "PUSH" ? (dropdownCategoryValues[_type] as DropdownValueType[])[ + selectedCategoryValue + ].value || CATEGORY.ERC20 : "ROLES" + + let subCategory = "DEFAULT" + if(_type === "PUSH"){ + if(category === CATEGORY.ERC20 || category === CATEGORY.ERC721){ + subCategory = tokenCategoryValues[selectedSubCategoryValue].value + } + } + + const getData = (type:string, category:string):Data=>{ + if(type === "PUSH"){ + if(category === CATEGORY.ERC20 || category === CATEGORY.ERC721){ + const selectedChain = dropdownChainsValues[selectedChainValue].value || 'eip155:1'; + return { + contract: `${selectedChain}:${contract}`, + amount: quantity.value, + decimals: 18, + } + }else if(category === CATEGORY.INVITE){ + return{ + inviterRoles: inviteCheckboxes.admin ? "ADMIN" : "OWNER" + } + }else{ + // CATEGORY.CustomEndpoint + // TODO: validate url + return{ + url:url + } + } + }else{ + // GUILD type + return { + id:guildId, + comparison:guildComparison, + role:guildComparison === 'specific' ? specificRoleId : "*", + } + } + } + + const rule:Rule = { + type: _type, + category: category, + subcategory: subCategory, + data: getData(_type, category), + } + + entryCriteria.addNewRule(rule) + + // alert(`${JSON.stringify(rule)}`) + + if(handlePrevious){ + handlePrevious() + } + + } + + // Autofill the form for the update + useEffect(()=>{ + if(entryCriteria.isUpdateCriteriaEnabled()){ + //Load the states + const oldValue = entryCriteria.entryOptionsDataArray[entryCriteria.entryOptionsDataArrayUpdate][entryCriteria.updateCriteriaIdx] + + if(oldValue.type === 'PUSH'){ + + // category + setSelectedCategoryValue( + (dropdownCategoryValues.PUSH as DropdownValueType[]).findIndex(obj => obj.value === oldValue.category) + ) + + const pushData = oldValue.data as PushData + + // sub category + if(oldValue.category === CATEGORY.ERC20 || oldValue.category === CATEGORY.ERC721){ + setSelectedSubCategoryValue( + tokenCategoryValues.findIndex(obj => obj.value === oldValue.subcategory) + ) + + const contractAndChain:string[] = (pushData.contract || "eip155:1:0x").split(':') + setSelectedChainValue( + dropdownChainsValues.findIndex( + obj => obj.value === contractAndChain[0]+":"+contractAndChain[1] + ) + ) + setContract(contractAndChain.length === 3 ? contractAndChain[2]: "") + setQuantity({value:pushData.amount || 0, range:0}) + }else if(oldValue.category === CATEGORY.INVITE){ + setInviteCheckboxes({ + admin:pushData.inviterRoles === "ADMIN", + owner:pushData.inviterRoles === "OWNER", + }) + }else{ + // invite + setUrl(pushData.url || "") + } + }else{ + // guild condition + alert(`${JSON.stringify(oldValue.data)}`) + setGuildId((oldValue.data as GuildData).id) + setSpecificRoleId((oldValue.data as GuildData).role) + setGuildComparison((oldValue.data as GuildData).comparison) + } + + setSelectedTypeValue( + dropdownTypeValues.findIndex(obj => obj.value === oldValue.type) + ) + } + },[]) + return (
- setSpecificRoleId(e.target.value)} - placeholder="e.g. 4687" - /> + {guildComparison === "specific" && + setSpecificRoleId(e.target.value)} + placeholder="e.g. 4687" + /> + } + + )} - @@ -407,4 +520,3 @@ const AddCriteria = ({ export default AddCriteria; -//styles diff --git a/packages/uiweb/src/lib/components/chat/CreateGroup/ConditionsComponent.tsx b/packages/uiweb/src/lib/components/chat/CreateGroup/ConditionsComponent.tsx index e29dec45a..aff16eebe 100644 --- a/packages/uiweb/src/lib/components/chat/CreateGroup/ConditionsComponent.tsx +++ b/packages/uiweb/src/lib/components/chat/CreateGroup/ConditionsComponent.tsx @@ -21,6 +21,8 @@ export type CriteraValueType = { interface CriteriaProps { conditionData: ConditionArray[]; + deleteFunction?:(idx:number)=>void; + updateFunction?:(idx:number)=>void; } interface MoreOptionsContainerProps { @@ -82,8 +84,8 @@ const CriteriaSection = ({ criteria }: { criteria: ConditionData }) => { ); }; -// fix dropdown ui -const ConditionsComponent = ({ conditionData }: CriteriaProps) => { +// fix dropdown ui +const ConditionsComponent = ({ conditionData,deleteFunction,updateFunction }: CriteriaProps) => { const [selectedIndex, setSelectedIndex] = useState | null>( null ); @@ -97,7 +99,11 @@ const ConditionsComponent = ({ conditionData }: CriteriaProps) => { title: 'Edit', icon: EditSvg, function: () => { - console.log('function to edit'); + if(updateFunction){ + if(selectedIndex){ + updateFunction(selectedIndex[0]) + } + } }, }, { @@ -106,7 +112,11 @@ const ConditionsComponent = ({ conditionData }: CriteriaProps) => { title: 'Remove', icon: RemoveSvg, function: () => { - console.log('function to remove'); + if(deleteFunction){ + if(selectedIndex){ + deleteFunction(selectedIndex[0]) + } + } }, }, ]; @@ -114,11 +124,10 @@ const ConditionsComponent = ({ conditionData }: CriteriaProps) => { useClickAway(dropdownRef, () => setSelectedIndex(null)); - //fix the theming - const handleMoreOptionsClick = (row: number, col: number) => { setSelectedIndex([row, col]); }; + return (
{conditionData && diff --git a/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupModal.tsx b/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupModal.tsx index 9390eb960..76f28c7d8 100644 --- a/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupModal.tsx +++ b/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupModal.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useRef, useState } from 'react'; +import React, { useContext, useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; import { AiTwotoneCamera } from 'react-icons/ai'; @@ -23,6 +23,8 @@ import AddCriteria from './AddCriteria'; import { SpamIcon } from '../../../icons/SpamIcon'; import { ThemeContext } from '../theme/ThemeProvider'; import { ToastContainer } from 'react-toastify'; +import { CriteriaStateType} from '../types/tokenGatedGroupCreationType'; +import { useCriteriaState } from '../../../hooks/chat/useCriteriaState'; export const CREATE_GROUP_STEP_KEYS = { INPUT_DETAILS: 1, @@ -50,13 +52,23 @@ export const CreateGroupModal: React.FC = ({ ); const handleNext = () => { - console.log('active') setActiveComponent(activeComponent+1 as CreateGroupStepKeys); - console.log(activeComponent) }; const handlePrevious = () => { setActiveComponent(activeComponent-1 as CreateGroupStepKeys); }; + + const entryCriteria = useCriteriaState() + + useEffect(()=>{ + // reset update rules + if(activeComponent === 2){ + entryCriteria.selectEntryOptionsDataArrayForUpdate(-1) + entryCriteria.setSelectedRule([]) + }else if(activeComponent === 3){ + entryCriteria.setUpdateCriteriaIdx(-1) + } + },[activeComponent]) const [groupInputDetails, setGroupInputDetails] = useState({ groupName:'', @@ -64,23 +76,25 @@ export const CreateGroupModal: React.FC = ({ groupImage:null }) + const renderComponent = () => { switch (activeComponent) { case CREATE_GROUP_STEP_KEYS.INPUT_DETAILS: return ; case CREATE_GROUP_STEP_KEYS.GROUP_TYPE: - return ; + return ; case CREATE_GROUP_STEP_KEYS.DEFINITE_CONDITION: - return + return case CREATE_GROUP_STEP_KEYS.ADD_CRITERIA: - return + return default: - return ; } }; @@ -92,6 +106,7 @@ export interface ModalHeaderProps { handleNext?: () => void; handlePrevious?:() =>void; onClose: () => void; + entryCriteria:CriteriaStateType; } interface GroupDetailState{ @@ -142,22 +157,26 @@ const CreateGroupDetail = ({handleNext, onClose, groupInputDetails, setGroupInpu } const verifyAndHandelNext = ()=>{ - // verify name - if (groupName.trim().length === 0){ - showError("Group Name is empty") - return - } - - // verify description - if (groupDescription.trim().length === 0){ - showError("Group Description is empty") - return - } - - // verify description - if (!groupImage){ - showError("Group image can't be empty") - return + const skipVerify = true; + + if(!skipVerify){ + // verify name + if (groupName.trim().length === 0){ + showError("Group Name is empty") + return + } + + // verify description + if (groupDescription.trim().length === 0){ + showError("Group Description is empty") + return + } + + // verify description + if (!groupImage){ + showError("Group image can't be empty") + return + } } if(handleNext){ diff --git a/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupType.tsx b/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupType.tsx index 1a068326f..fc1d3272f 100644 --- a/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupType.tsx +++ b/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupType.tsx @@ -1,7 +1,5 @@ -import React, { useContext, useState } from 'react'; - +import { useContext, useState } from 'react'; import { MdError } from 'react-icons/md'; - import { ModalHeader } from '../reusables/Modal'; import OptionButtons, { OptionDescription } from '../reusables/OptionButtons'; import { Section, Span } from '../../reusables'; @@ -11,11 +9,13 @@ import { GatingRulesInformation, ModalHeaderProps } from './CreateGroupModal'; import { GroupTypeState } from './CreateGroupModal'; import { ThemeContext } from '../theme/ThemeProvider'; -import useMediaQuery from '../../../hooks/useMediaQuery'; -import { device } from '../../../config'; import useToast from '../reusables/NewToast'; import { OPERATOR_OPTIONS, OPERATOR_OPTIONS_INFO } from '../constants'; import { ConditionArray, IChatTheme } from '../exportedTypes'; +import { + ConditionType, + CriteriaStateType, +} from '../types/tokenGatedGroupCreationType'; import ConditionsComponent from './ConditionsComponent'; import { OperatorContainer } from './OperatorContainer'; import styled from 'styled-components'; @@ -48,87 +48,24 @@ interface AddConditionProps { heading: string; subHeading: string; handleNext?: () => void; + criteriaState: CriteriaStateType; } + const AddConditionSection = ({ heading, subHeading, handleNext, + criteriaState, }: AddConditionProps) => { + const theme = useContext(ThemeContext); //todo - dummy data to be removed after we get condition data - const dummyConditonsData: ConditionArray[] = [ - [{ operator: 'any' }], - [ - { - type: 'PUSH', - category: 'ERC20', - subcategory: 'holder', - data: { - contract: 'eip155:1:0xf418588522d5dd018b425E472991E52EBBeEEEEE', - amount: 1, - decimals: 18, - }, - }, - ], - [ - { operator: 'all' }, - { - type: 'PUSH', - category: 'ERC20', - subcategory: 'holder', - data: { - contract: 'eip155:137:0x58001cC1A9E17A20935079aB40B1B8f4Fc19EFd1', - amount: 1, - decimals: 18, - }, - }, - { - type: 'PUSH', - category: 'ERC721', - subcategory: 'holder', - data: { - contract: 'eip155:137:0x58001cC1A9E17A20935079aB40B1B8f4Fc19EFd1', - amount: 1, - decimals: 18, - }, - }, - { - type: 'GUILD', - category: 'ROLES', - subcategory: 'DEFAULT', - data: { - id: '1', - role: '346243', - comparison: 'all', - }, - }, - ], - [ - { operator: 'any' }, - { - type: 'PUSH', - category: 'INVITE', - subcategory: 'DEFAULT', - data: { - inviterRoles: 'ADMIN', - }, - }, - { - type: 'PUSH', - category: 'INVITE', - subcategory: 'DEFAULT', - data: { - inviterRoles: 'OWNER', - }, - }, - ], - ]; - - const dummySingleCondtionData = dummyConditonsData[2]; - const theme = useContext(ThemeContext); - const [conditionOperator, setConditionOperator] = useState( - dummyConditonsData[0][0]?.operator as string - ); + const generateMapping = () => { + return criteriaState.entryOptionsDataArray.map((rule, idx) => [ + { operator: criteriaState.entryOptionTypeArray[idx] }, + ...rule.map((el) => el), + ]); + }; return (
@@ -151,16 +88,44 @@ const AddConditionSection = ({
{ + criteriaState.setEntryRootCondition(newEl as ConditionType); + }} />
- - + + { + criteriaState.deleteEntryOptionsDataArray(idx); + }} + updateFunction={(idx) => { + criteriaState.selectEntryOptionsDataArrayForUpdate(idx); + if (handleNext) { + handleNext(); + } + }} + />
); }; +const ConditionSection = styled(Section)<{ theme: IChatTheme }>` + &::-webkit-scrollbar-thumb { + background: ${(props) => props.theme.scrollbarColor}; + border-radius: 10px; + } -const ConditionSection = styled(Section)<{theme:IChatTheme}>` -&::-webkit-scrollbar-thumb { - background: ${(props) => props.theme.scrollbarColor}; - border-radius: 10px; -} - -&::-webkit-scrollbar-button { - height: 40px; -} + &::-webkit-scrollbar-button { + height: 40px; + } -&::-webkit-scrollbar { - width: 4px; -} -`; \ No newline at end of file + &::-webkit-scrollbar { + width: 4px; + } +`; diff --git a/packages/uiweb/src/lib/components/chat/constants/index.ts b/packages/uiweb/src/lib/components/chat/constants/index.ts index db890f9c0..e8b08ac4e 100644 --- a/packages/uiweb/src/lib/components/chat/constants/index.ts +++ b/packages/uiweb/src/lib/components/chat/constants/index.ts @@ -11,7 +11,7 @@ export const INVITE_CHECKBOX_LABEL: { owner: string; admin: string } = { value: 'all', }, { - heading: 'ALL', + heading: 'ANY', value: 'any', }, { @@ -33,11 +33,13 @@ export const INVITE_CHECKBOX_LABEL: { owner: string; admin: string } = { export const OPERATOR_OPTIONS_INFO = { - any:{ head:'Any one', - tail:'of the following criteria must be true' - }, - all:{ head:'All', - tail:'of the following criteria must be true' - } + any:{ + head:'Any one', + tail:'of the following criteria must be true' + }, + all:{ + head:'All', + tail:'of the following criteria must be true' + } } ; diff --git a/packages/uiweb/src/lib/components/chat/helpers/tokenGatedGroup.ts b/packages/uiweb/src/lib/components/chat/helpers/tokenGatedGroup.ts new file mode 100644 index 000000000..9ba151373 --- /dev/null +++ b/packages/uiweb/src/lib/components/chat/helpers/tokenGatedGroup.ts @@ -0,0 +1,25 @@ +import { CriteriaStateType, Data } from '../types'; +import { DropdownValueType } from '../reusables'; +import { CATEGORY, DropdownCategoryValuesType } from '../types'; + +const handleDefineCondition = ( + entryCriteria: CriteriaStateType, + handlePrevious: (() => void) | undefined +) => { + if (entryCriteria.isCondtionUpdateEnabled()) { + // handle update + entryCriteria.updateCondition(); + } else { + // handle insertion + entryCriteria.addNewCondtion(); + } + + if (handlePrevious) { + handlePrevious(); + } +}; + + + + +export {handleDefineCondition} diff --git a/packages/uiweb/src/lib/components/chat/types/index.ts b/packages/uiweb/src/lib/components/chat/types/index.ts index a84d75ff1..4801c4f04 100644 --- a/packages/uiweb/src/lib/components/chat/types/index.ts +++ b/packages/uiweb/src/lib/components/chat/types/index.ts @@ -44,3 +44,5 @@ export type DropdownCategoryValuesType = { export type DropdownSubCategoryValuesType = { [key in SubCategoryKeys]: InputType; }; + +export * from './tokenGatedGroupCreationType' \ No newline at end of file diff --git a/packages/uiweb/src/lib/components/chat/types/tokenGatedGroupCreationType.ts b/packages/uiweb/src/lib/components/chat/types/tokenGatedGroupCreationType.ts new file mode 100644 index 000000000..cc510d634 --- /dev/null +++ b/packages/uiweb/src/lib/components/chat/types/tokenGatedGroupCreationType.ts @@ -0,0 +1,69 @@ +export interface PushData { + contract?: string; + amount?: number; + decimals?: number; + inviterRoles?: 'OWNER' | 'ADMIN'; + url?: string; +} + +export interface GuildData { + id: string; + role: string; + comparison: string; +} + +export type Data = PushData | GuildData; + +export interface Rule { + type: 'PUSH' | 'GUILD'; + // category: 'ERC20' | 'ERC721'; + category: string; + subcategory: string; + data: Data; +} + +export type Condition = Rule | AnyCondition | AllCondition; + +export interface AnyCondition { + any: Condition[]; +} + +export interface AllCondition { + all: Condition[]; +} + +export interface ChatConditions { + conditions: AllCondition | AnyCondition; +} + +export type ConditionType = 'any' | 'all'; + +export interface CriteriaStateType { + entryRootCondition: ConditionType; + setEntryRootCondition: React.Dispatch>; + entryRuleTypeCondition: ConditionType; + setEntryRuleTypeCondition: React.Dispatch< + React.SetStateAction + >; + entryOptionTypeArray: ConditionType[]; + setEntryOptionTypeArray: React.Dispatch< + React.SetStateAction + >; + entryOptionsDataArray: Rule[][]; + setEntryOptionsDataArray: React.Dispatch>; + selectedCriteria: number; + setSelectedCriteria: React.Dispatch>; + selectedRules: Rule[]; + setSelectedRule: React.Dispatch>; + addNewCondtion: () => void; + addNewRule: (newRule: Rule) => void; + deleteRule: (idx: number) => void; + deleteEntryOptionsDataArray: (idx: number) => void; + selectEntryOptionsDataArrayForUpdate: (idx: number) => void; + entryOptionsDataArrayUpdate: number; + isCondtionUpdateEnabled: () => boolean; + updateCondition: () => void; + updateCriteriaIdx: number; + setUpdateCriteriaIdx: React.Dispatch>; + isUpdateCriteriaEnabled: () => boolean; +} diff --git a/packages/uiweb/src/lib/components/notification/chainDetails.tsx b/packages/uiweb/src/lib/components/notification/chainDetails.tsx index ad783c516..403f12c39 100644 --- a/packages/uiweb/src/lib/components/notification/chainDetails.tsx +++ b/packages/uiweb/src/lib/components/notification/chainDetails.tsx @@ -7,7 +7,7 @@ import { BSCSvg } from "../../icons/BSCSvg"; import { OptimismSvg } from "../../icons/OptimismSvg"; import { PolygonzkevmSvg } from "../../icons/PolygonzkevmSvg"; import { TheGraphSvg } from "../../icons/TheGraphSvg"; -import { ReactElement } from "react"; +import { ArbitrumSvg } from "../../icons/ArbitrumSvg" const createSVGIcon = (element:any, chainName: string) => { return ( @@ -58,5 +58,14 @@ export default { label: 'POLYGON ZK EVM MAINNET', icon: createSVGIcon(, 'Polygon ZK EVM Mainnet'), }, + + ARBITRUMONE_MAINNET: { + label: 'ARBITRUMONE MAINNET', + icon: createSVGIcon(, 'Arbitrum Mainnet'), + }, + ARBITRUM_TESTNET: { + label: 'ARBITRUM TESTNET', + icon: createSVGIcon(, 'Arbitrum Testnet'), + }, THE_GRAPH: { label: 'THE GRAPH', icon: createSVGIcon(, 'The Graph') }, }; diff --git a/packages/uiweb/src/lib/components/notification/index.tsx b/packages/uiweb/src/lib/components/notification/index.tsx index bcec3907b..8ce4dd911 100644 --- a/packages/uiweb/src/lib/components/notification/index.tsx +++ b/packages/uiweb/src/lib/components/notification/index.tsx @@ -34,6 +34,8 @@ export type chainNameType = | 'OPTIMISM_TESTNET' | 'POLYGON_ZK_EVM_TESTNET' | 'POLYGON_ZK_EVM_MAINNET' + | 'ARBITRUMONE_MAINNET' + | 'ARBITRUM_TESTNET' | 'THE_GRAPH' | undefined; diff --git a/packages/uiweb/src/lib/config/constants.ts b/packages/uiweb/src/lib/config/constants.ts index 7d6ff08d9..1c82dc065 100644 --- a/packages/uiweb/src/lib/config/constants.ts +++ b/packages/uiweb/src/lib/config/constants.ts @@ -113,4 +113,4 @@ export const requestLimit = 10; export const notificationLimit = 5; export const FILE_ICON = (extension: string) => - `https://cdn.jsdelivr.net/gh/napthedev/file-icons/file/${extension}.svg`; + `https://cdn.jsdelivr.net/gh/napthedev/file-icons/file/${extension}.svg`; \ No newline at end of file diff --git a/packages/uiweb/src/lib/hooks/chat/useCriteriaState.ts b/packages/uiweb/src/lib/hooks/chat/useCriteriaState.ts new file mode 100644 index 000000000..266b9adad --- /dev/null +++ b/packages/uiweb/src/lib/hooks/chat/useCriteriaState.ts @@ -0,0 +1,114 @@ +import { useState } from 'react'; +import { + ConditionType, + CriteriaStateType, + Rule, +} from '../../components/chat/types'; + +export const useCriteriaState = (): CriteriaStateType => { + const [entryRootCondition, setEntryRootCondition] = + useState('all'); + const [entryRuleTypeCondition, setEntryRuleTypeCondition] = + useState('all'); + const [entryOptionTypeArray, setEntryOptionTypeArray] = useState< + ConditionType[] + >([]); + const [entryOptionsDataArray, setEntryOptionsDataArray] = useState( + [] + ); + + const [selectedCriteria, setSelectedCriteria] = useState(-1); + const [selectedRules, setSelectedRule] = useState([]); + + const [entryOptionsDataArrayUpdate, setEntryOptionsDataArrayUpdate] = + useState(-1); + const [updateCriteriaIdx, setUpdateCriteriaIdx] = useState(-1); + + const addNewRule = (newRule: Rule) => { + if (selectedCriteria === -1) { + setSelectedCriteria(entryOptionTypeArray.length); + } + + if (updateCriteriaIdx !== -1) { + // update existing + const _rulesToUpdate = [...selectedRules]; + _rulesToUpdate[updateCriteriaIdx] = newRule; + setSelectedRule(_rulesToUpdate); + } else { + // add new + setSelectedRule((prev) => [...prev, newRule]); + } + }; + + const deleteRule = (idx: number) => { + const removedRule = [...selectedRules]; + removedRule.splice(idx, 1); + setSelectedRule(removedRule); + }; + + const addNewCondtion = () => { + setEntryOptionTypeArray((prev) => [...prev, entryRuleTypeCondition]); + setEntryOptionsDataArray((prev) => [...prev, [...selectedRules]]); + setSelectedRule([]); + }; + + const updateCondition = () => { + const optionTypeArrayUpdated = [...entryOptionTypeArray]; + optionTypeArrayUpdated[entryOptionsDataArrayUpdate] = + entryRuleTypeCondition; + + const entryOptionsDataArrayUpdated = [...entryOptionsDataArray]; + entryOptionsDataArrayUpdated[entryOptionsDataArrayUpdate] = [ + ...selectedRules, + ]; + + setEntryOptionTypeArray(optionTypeArrayUpdated); + setEntryOptionsDataArray(entryOptionsDataArrayUpdated); + + setSelectedRule([]); + }; + + const isCondtionUpdateEnabled = () => { + return entryOptionsDataArrayUpdate !== -1; + }; + + const deleteEntryOptionsDataArray = (idx: number) => { + const removedRule = [...entryOptionsDataArray]; + removedRule.splice(idx, 1); + setEntryOptionsDataArray(removedRule); + }; + + const selectEntryOptionsDataArrayForUpdate = (idx: number) => { + setEntryOptionsDataArrayUpdate(idx); + }; + + const isUpdateCriteriaEnabled = () => { + return updateCriteriaIdx !== -1; + }; + + return { + entryRootCondition, + setEntryRootCondition, + entryRuleTypeCondition, + setEntryRuleTypeCondition, + entryOptionTypeArray, + setEntryOptionTypeArray, + entryOptionsDataArray, + setEntryOptionsDataArray, + selectedCriteria, + setSelectedCriteria, + addNewCondtion, + selectedRules, + addNewRule, + deleteRule, + deleteEntryOptionsDataArray, + selectEntryOptionsDataArrayForUpdate, + entryOptionsDataArrayUpdate, + isCondtionUpdateEnabled, + updateCondition, + setSelectedRule, + updateCriteriaIdx, + setUpdateCriteriaIdx, + isUpdateCriteriaEnabled, + }; +}; diff --git a/packages/uiweb/src/lib/icons/ArbitrumSvg.tsx b/packages/uiweb/src/lib/icons/ArbitrumSvg.tsx new file mode 100644 index 000000000..5703e7717 --- /dev/null +++ b/packages/uiweb/src/lib/icons/ArbitrumSvg.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; + +export const ArbitrumSvg = () => ( + + + + + +); +