diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml new file mode 100644 index 000000000..5dc22b08f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -0,0 +1,79 @@ +name: "🐛 Bug Report" +description: Create a bug report to help us improve. +title: "🐛 [BUG] - " +labels: [ + "bug" +] +body: + - type: textarea + id: expected-behaviour + attributes: + label: "Expected Behaviour" + description: Please describe the behavior you are expecting + placeholder: Short and explicit description of your desired behaviour... + validations: + required: true + - type: textarea + id: current-behaviour + attributes: + label: "Current Behaviour" + description: Please describe the current behavior + placeholder: What is the current behavior?... + validations: + required: true + - type: textarea + id: reprod + attributes: + label: "Reproduction steps" + description: Please enter an explicit description of your issue + value: | + 1. Go to '...' + 2. Invoke function '...' + 3. See error + render: bash + validations: + required: true + - type: textarea + id: screenshot + attributes: + label: "Screenshots" + description: If applicable, add screenshots to help explain your problem. + value: | + ![DESCRIPTION](LINK.png) + render: bash + validations: + required: false + - type: textarea + id: logs + attributes: + label: "Relevant Logs" + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: bash + validations: + required: false + - type: dropdown + id: dapp-env + attributes: + label: "Dapp Env" + description: What is the impacted DApp environment ? + multiple: true + options: + - Prod (app.push.org) + - Staging (staging.push.org) + - Dev (dev.push.org) + validations: + required: true + - type: dropdown + id: browsers + attributes: + label: "Browsers" + description: What browsers are you seeing the problem on ? + multiple: true + options: + - Firefox + - Chrome + - Safari + - Microsoft Edge + - Opera + validations: + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/DOCUMENTATION_README_ISSUE.yml b/.github/ISSUE_TEMPLATE/DOCUMENTATION_README_ISSUE.yml new file mode 100644 index 000000000..36ad7abc6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/DOCUMENTATION_README_ISSUE.yml @@ -0,0 +1,35 @@ +name: "✏️ Documentation/Readme Enhancement" +description: Suggest an enhancement in documentation/readme. +title: "✏️ [Documentation/Readme Enhancement] - <title>" +labels: [ + "documentation" +] +body: + - type: textarea + id: expected-behaviour + attributes: + label: "Expected Behaviour" + description: Please describe the behavior you are expecting + placeholder: Short and explicit description of your desired behaviour... + validations: + required: false + - type: textarea + id: current-behaviour + attributes: + label: "Current Behaviour" + description: Please describe the current behavior + placeholder: What is the current behavior?... + validations: + required: false + - type: textarea + id: reprod + attributes: + label: "Steps to Reproduce" + description: Please enter an explicit description of your issue + value: | + 1. Go to '...' + 2. Invoke function '...' + 3. See error + render: bash + validations: + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/IMPROVEMENT_PROPOSAL.yml b/.github/ISSUE_TEMPLATE/IMPROVEMENT_PROPOSAL.yml new file mode 100644 index 000000000..3f062784e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/IMPROVEMENT_PROPOSAL.yml @@ -0,0 +1,40 @@ +name: "😈 Improvement Proposal" +description: Suggest improvement,whether new or built upon existing features. +title: "😈 [Improvement Proposal] - <title>" +labels: [ + "Improvement proposal" +] +body: + - type: input + id: proposal-name + attributes: + label: "Proposal name" + description: Brief title or summary of the proposed improvement. + placeholder: Summary of the proposal improvement. + validations: + required: true + - type: textarea + id: description + attributes: + label: "Describe the Proposal" + description: Please describe detailed description of the improvement, including the problem it solves and the benefits it brings. + placeholder: Detailed description of your desired proposal... + validations: + required: true + - type: textarea + id: usecase + attributes: + label: "Use Case" + description: Please explain the specific use cases or scenarios where this improvement would be valuable.. + placeholder: List down the use case. + validations: + required: true + - type: textarea + id: current-limitations + attributes: + label: "Current Limitations" + description: Any existing limitations, issues, or challenges with the SDK that the proposed improvement aims to address. + placeholder: Overview for the current problem/limitations. + validations: + required: true + \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/OTHER.yml b/.github/ISSUE_TEMPLATE/OTHER.yml new file mode 100644 index 000000000..21941d88a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/OTHER.yml @@ -0,0 +1,27 @@ +name: "👾 Other" +description: Something that doesn't belong elsewhere. +title: "👾 [Other] - <title>" +labels: [ + "Other" +] +body: + - type: textarea + id: description + attributes: + label: "Description" + description: Please describe something + placeholder: Detailed description of what you wanna share... + validations: + required: true + - type: dropdown + id: dapp-env + attributes: + label: "Dapp Env" + description: What is the impacted DApp environment ? + multiple: true + options: + - Prod (app.push.org) + - Staging (staging.push.org) + - Dev (dev.push.org) + validations: + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/QUESTION_SUPPORT.yml b/.github/ISSUE_TEMPLATE/QUESTION_SUPPORT.yml new file mode 100644 index 000000000..2085f49e5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/QUESTION_SUPPORT.yml @@ -0,0 +1,15 @@ +name: "❓ Question or Support Request" +description: Questions and requests for support. +title: "❓ [Question/Support] - <title>" +labels: [ + "support" +] +body: + - type: textarea + id: support-request + attributes: + label: "Question or Support Request" + description: Describe your question or ask for support. + placeholder: Detailed description of your question/support request... + validations: + required: true \ No newline at end of file diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 000000000..c8ba01326 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,35 @@ +EXAMPLE USAGE: + + Refer for explanation to following link: + https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md + +pre-push: + commands: + packages-audit: + tags: frontend security + run: yarn audit + gems-audit: + tags: backend security + run: bundle audit + +pre-commit: + parallel: true + commands: + eslint: + glob: "*.{js,ts,jsx,tsx}" + run: yarn eslint {staged_files} + rubocop: + tags: backend style + glob: "*.rb" + exclude: "application.rb|routes.rb" + run: bundle exec rubocop --force-exclusion {all_files} + govet: + tags: backend style + files: git ls-files -m + glob: "*.go" + run: go vet {files} + scripts: + "hello.js": + runner: node + "any.go": + runner: go run diff --git a/packages/examples/notification-setting/.env.sample b/packages/examples/notification-setting/.env.sample new file mode 100644 index 000000000..f7e8f8c67 --- /dev/null +++ b/packages/examples/notification-setting/.env.sample @@ -0,0 +1,2 @@ +PRIVATE_KEY=your_private_key +RPC=your_rpc \ No newline at end of file diff --git a/packages/examples/notification-setting/README.md b/packages/examples/notification-setting/README.md new file mode 100644 index 000000000..949e8c5c6 --- /dev/null +++ b/packages/examples/notification-setting/README.md @@ -0,0 +1,18 @@ +## Notification Setting Example + + +## Usecase highlighted + +This example shows the end-to-end process of + - Creating a channel + - Defining the setting, + - Make user subscribe to the channel for the settings they are interested, + - Trigger a notification + - At last list down the notifications + +Note: It is recommended to use the `.env` to put your private key for testing and make sure the wallet is funded with ether and PUSH tokens. For this, rename `.env.sample` to `.env`. + +## Install instructions +1. Navigate to this directory from the terminal +2. do `npm install` or `yarn install` +3. do `yarn start` \ No newline at end of file diff --git a/packages/examples/notification-setting/index.js b/packages/examples/notification-setting/index.js new file mode 100644 index 000000000..0dbead223 --- /dev/null +++ b/packages/examples/notification-setting/index.js @@ -0,0 +1,171 @@ +import { PushAPI } from '@pushprotocol/restapi'; +import { ethers } from 'ethers'; +import * as dotenv from 'dotenv'; +dotenv.config(); + +// initialise the provider +const provider = new ethers.providers.JsonRpcProvider( + // PUBLIC RPC + process.env?.RPC?? 'https://goerli.blockpi.network/v1/rpc/public' +); + +let signer; +if (process.env.PRIVATE_KEY) { + signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider); + console.log('Using the wallet from .env: %s', signer.address); +} else { + signer = ethers.Wallet.createRandom().connect(provider); + console.log('Fund your wallet with eth and PUSH token: %s', signer.address); +} + +// initialise the sdk with the signer and env +// for channel +const userAlice = await PushAPI.initialize(signer, { env: 'staging' }); +// for subscribers +const userBob = await PushAPI.initialize( + ethers.Wallet.createRandom().connect(provider), + { env: 'staging' } +); + + +const userKate = await PushAPI.initialize( + ethers.Wallet.createRandom().connect(provider), + { env: 'staging' } +); + +const main = async () => { + try { + // create the channel + const createChannelRes = await userAlice.channel.create({ + // name of the channel + name: 'Test 123', + // channel description + description: 'Gm gm PUSH fam', + // url of the channel + url: 'https://push.org', + // base64 icon + icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAz0lEQVR4AcXBsU0EQQyG0e+saWJ7oACiKYDMEZVs6GgSpC2BIhzRwAS0sgk9HKn3gpFOAv3v3V4/3+4U4Z1q5KTy42Ql940qvFONnFSGmCFmiN2+fj7uCBlihpgh1ngwcvKfwjuVIWaIGWKNB+GdauSk8uNkJfeNKryzYogZYoZY40m5b/wlQ8wQM8TayMlKeKcaOVkJ71QjJyuGmCFmiDUe+HFy4VyEd57hx0mV+0ZliBlihlgL71w4FyMnVXhnZeSkiu93qheuDDFDzBD7BcCyMAOfy204AAAAAElFTkSuQmCC', + }); + console.log("Channel created with hash: %s", createChannelRes.transactionHash); + + // create settings + const settingRes = await userAlice.channel.setting([ + { + type: 1, + description: 'Setting1', + default: 1, + }, + { + type: 2, + description: 'Setting2', + default: 10, + data: { + upper: 100, + lower: 1, + enabled: true, + ticker: 5, + }, + }, + ]); + + console.log(settingRes) + + // fetch channel info with the settings + const channelInfoWithSetting = await userAlice.channel.info(); + console.log('Channel info with settings'); + console.log(channelInfoWithSetting); + + // make bob and kate subscribe to the channel + // bob wants to opt in to all the settings + await userBob.notification.subscribe( + `eip155:5:${userAlice.account}`, + { + settings: [ + // enabled for boolean type + { + enabled: true, + }, + { + // enabled for slider type when value is 10 + enabled: true, + value: 10, + }, + ], + } + ); + // kate doesnot want to opt in to any settings + await userKate.notification.subscribe( + `eip155:5:${userAlice.account}`, + { + settings: [ + // disabled for boolean type + { + enabled: false, + }, + { + // disabled for slider type and pass 0 as value + enabled: false, + value: 0, + }, + ], + } + ); + + // fetch Bob's subscription + const bobSubscriptions = await userBob.notification.subscriptions(); + console.log("Bob's subcriptions: "); + console.log(bobSubscriptions); + + // fetch Kate's subscription + const kateSubscriptions = await userKate.notification.subscriptions(); + console.log("Kate's subcriptions: "); + console.log(kateSubscriptions); + + // Trigger broadcast for slider type + const notifResForSlider = await userAlice.channel.send(['*'], { + notification: { + title: 'gm gm slider', + body: 'Sending notification with category 2', + }, + payload: { + title: 'testing first notification', + body: 'testing with random body', + cta: 'https://google.com/', + embed: 'https://avatars.githubusercontent.com/u/64157541?s=200&v=4', + // index of the notification the channel wants to trigger, in this for 2nd index which is for Setting2 type + category: 2, + }, + }); + + // Trigger broadcast for boolean type + const notifResForBoolean = await userAlice.channel.send(['*'], { + notification: { + title: 'gm gm boolean', + body: 'Sending notification with category 1', + }, + payload: { + title: 'testing first notification', + body: 'testing with random body', + cta: 'https://google.com/', + embed: 'https://avatars.githubusercontent.com/u/64157541?s=200&v=4', + // index of the notification the channel wants to trigger, in this for 1st index which is for Setting12 type + category: 1, + }, + }); + + // List the inbox of Bob + const bobList = await userBob.notification.list() + console.log("Bob's notification list") + console.log(bobList) + + // List down inbox of Kate + const kateList = await userKate.notification.list() + console.log("Kate's notification list") + console.log(kateList) + + } catch (error) { + console.log(error); + } +}; + +main(); diff --git a/packages/examples/notification-setting/package.json b/packages/examples/notification-setting/package.json new file mode 100644 index 000000000..49be67491 --- /dev/null +++ b/packages/examples/notification-setting/package.json @@ -0,0 +1,23 @@ +{ + "name": "notification-setting", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "build": "rimraf ./build && tsc", + "start": "nodemon", + "inspect": "nodemon --inspect index.js", + "dev": "node-dev --respawn --transpile-only index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@pushprotocol/restapi": "^1.4.30" + }, + "devDependencies": { + "nodemon": "^3.0.1" + } +} diff --git a/packages/examples/sdk-backend-node/package.json b/packages/examples/sdk-backend-node/package.json index a75fdb60c..6de585357 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.44", + "@pushprotocol/restapi": "0.0.1-alpha.50", "@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 index 7e6b236a0..c33154a92 100644 --- a/packages/examples/sdk-backend-node/pushAPI/channel.ts +++ b/packages/examples/sdk-backend-node/pushAPI/channel.ts @@ -143,7 +143,7 @@ export const runPushAPIChannelCases = async (): Promise<void> => { // ------------------------------------------------------------------- console.log('PushAPI.channel.setting'); const channelSettingTrx = await userAlice.channel.setting([ - { type: 0, default: 1, description: 'My Notif Settings' }, + { type: 1, default: 1, description: 'My Notif Settings' }, ]); if (showAPIResponse) { console.log(channelSettingTrx); diff --git a/packages/examples/sdk-frontend-react/src/app/ChatUITest/ChatViewComponent.tsx b/packages/examples/sdk-frontend-react/src/app/ChatUITest/ChatViewComponent.tsx index 387f902bb..93b49170c 100644 --- a/packages/examples/sdk-frontend-react/src/app/ChatUITest/ChatViewComponent.tsx +++ b/packages/examples/sdk-frontend-react/src/app/ChatUITest/ChatViewComponent.tsx @@ -13,6 +13,7 @@ const ChatViewComponentTest = () => { return ( <div> <h2>Chat UI Test page</h2> + <CreateGroupModal onClose={()=>{console.log('in close')}} /> <ChatViewComponentCard> <CreateGroupModal onClose={()=>{console.log('in close')}} modalBackground={MODAL_BACKGROUND_TYPE.OVERLAY} modalPositionType={MODAL_POSITION_TYPE.RELATIVE}/> diff --git a/packages/examples/sdk-frontend/pages/index.tsx b/packages/examples/sdk-frontend/pages/index.tsx index 936704b2c..e95310d1b 100644 --- a/packages/examples/sdk-frontend/pages/index.tsx +++ b/packages/examples/sdk-frontend/pages/index.tsx @@ -1,4 +1,4 @@ -import { ConnectButtonComp } from '@rainbow-me/rainbowkit'; +import { ConnectButton } from '@rainbow-me/rainbowkit'; import { NextPage } from 'next'; import Link from 'next/link'; import styled from 'styled-components'; @@ -7,7 +7,7 @@ const Index: NextPage = () => { return ( <Container> <h1>Hello Next.js 👋</h1> - <ConnectButtonComp /> + <ConnectButton /> <Button> <Link href="/video">Video</Link> </Button> diff --git a/packages/examples/sdk-frontend/pages/video.tsx b/packages/examples/sdk-frontend/pages/video.tsx index a44a90ac3..2b99b8abf 100644 --- a/packages/examples/sdk-frontend/pages/video.tsx +++ b/packages/examples/sdk-frontend/pages/video.tsx @@ -1,6 +1,4 @@ import type { NextPage } from 'next'; -import Head from 'next/head'; -import { ConnectButton } from '@rainbow-me/rainbowkit'; import * as PushAPI from '@pushprotocol/restapi'; import { ENV } from '@pushprotocol/restapi/src/lib/constants'; @@ -242,10 +240,6 @@ const Home: NextPage = () => { <Heading>Push Video SDK Demo</Heading> <CallInfo>Video Call Status: {data.incoming[0].status}</CallInfo> - <HContainer> - <ConnectButtonComp /> - </HContainer> - {isConnected ? ( <> <HContainer> diff --git a/packages/examples/subgraph-notification/.gitignore b/packages/examples/subgraph-notification/.gitignore new file mode 100644 index 000000000..3c3629e64 --- /dev/null +++ b/packages/examples/subgraph-notification/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/examples/subgraph-notification/README.md b/packages/examples/subgraph-notification/README.md new file mode 100644 index 000000000..5f98144e3 --- /dev/null +++ b/packages/examples/subgraph-notification/README.md @@ -0,0 +1,2 @@ +# push-notitifcations-on-subgraph-mainnet +Integrating Push Protocol notifications on to The Graph Network diff --git a/packages/examples/subgraph-notification/abis/EPNSCore.json b/packages/examples/subgraph-notification/abis/EPNSCore.json new file mode 100644 index 000000000..850552bd0 --- /dev/null +++ b/packages/examples/subgraph-notification/abis/EPNSCore.json @@ -0,0 +1,126 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "_logic", "type": "address" }, + { "internalType": "address", "name": "_governance", "type": "address" }, + { + "internalType": "address", + "name": "_pushChannelAdmin", + "type": "address" + }, + { + "internalType": "address", + "name": "_pushTokenAddress", + "type": "address" + }, + { "internalType": "address", "name": "_wethAddress", "type": "address" }, + { + "internalType": "address", + "name": "_uniswapRouterAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_lendingPoolProviderAddress", + "type": "address" + }, + { "internalType": "address", "name": "_daiAddress", "type": "address" }, + { "internalType": "address", "name": "_aDaiAddress", "type": "address" }, + { "internalType": "uint256", "name": "_referralCode", "type": "uint256" } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { "stateMutability": "payable", "type": "fallback" }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { "internalType": "address", "name": "admin_", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newAdmin", "type": "address" } + ], + "name": "changeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "implementation_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { "stateMutability": "payable", "type": "receive" } +] diff --git a/packages/examples/subgraph-notification/abis/PushToken.json b/packages/examples/subgraph-notification/abis/PushToken.json new file mode 100644 index 000000000..bf76cd649 --- /dev/null +++ b/packages/examples/subgraph-notification/abis/PushToken.json @@ -0,0 +1,193 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [{ "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "spender", "type": "address" }, + { "name": "tokens", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "name": "success", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [{ "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "from", "type": "address" }, + { "name": "to", "type": "address" }, + { "name": "tokens", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "name": "success", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [{ "name": "", "type": "uint8" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "_totalSupply", + "outputs": [{ "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "tokenOwner", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "name": "balance", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [{ "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "name": "a", "type": "uint256" }, + { "name": "b", "type": "uint256" } + ], + "name": "safeSub", + "outputs": [{ "name": "c", "type": "uint256" }], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "to", "type": "address" }, + { "name": "tokens", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "name": "success", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "name": "a", "type": "uint256" }, + { "name": "b", "type": "uint256" } + ], + "name": "safeDiv", + "outputs": [{ "name": "c", "type": "uint256" }], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "name": "spender", "type": "address" }, + { "name": "tokens", "type": "uint256" }, + { "name": "data", "type": "bytes" } + ], + "name": "approveAndCall", + "outputs": [{ "name": "success", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "name": "a", "type": "uint256" }, + { "name": "b", "type": "uint256" } + ], + "name": "safeMul", + "outputs": [{ "name": "c", "type": "uint256" }], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "name": "tokenOwner", "type": "address" }, + { "name": "spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "name": "remaining", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "name": "a", "type": "uint256" }, + { "name": "b", "type": "uint256" } + ], + "name": "safeAdd", + "outputs": [{ "name": "c", "type": "uint256" }], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "payable": true, "stateMutability": "payable", "type": "fallback" }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "from", "type": "address" }, + { "indexed": true, "name": "to", "type": "address" }, + { "indexed": false, "name": "tokens", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "name": "tokenOwner", "type": "address" }, + { "indexed": true, "name": "spender", "type": "address" }, + { "indexed": false, "name": "tokens", "type": "uint256" } + ], + "name": "Approval", + "type": "event" + } +] diff --git a/packages/examples/subgraph-notification/contracts/PushToken.sol b/packages/examples/subgraph-notification/contracts/PushToken.sol new file mode 100644 index 000000000..424a53444 --- /dev/null +++ b/packages/examples/subgraph-notification/contracts/PushToken.sol @@ -0,0 +1,113 @@ +pragma solidity ^0.4.24; + +//Safe Math Interface + +contract SafeMath { + + function safeAdd(uint a, uint b) public pure returns (uint c) { + c = a + b; + require(c >= a); + } + + function safeSub(uint a, uint b) public pure returns (uint c) { + require(b <= a); + c = a - b; + } + + function safeMul(uint a, uint b) public pure returns (uint c) { + c = a * b; + require(a == 0 || c / a == b); + } + + function safeDiv(uint a, uint b) public pure returns (uint c) { + require(b > 0); + c = a / b; + } +} + + +//ERC Token Standard #20 Interface + +contract ERC20Interface { + function totalSupply() public constant returns (uint); + function balanceOf(address tokenOwner) public constant returns (uint balance); + function allowance(address tokenOwner, address spender) public constant returns (uint remaining); + function transfer(address to, uint tokens) public returns (bool success); + function approve(address spender, uint tokens) public returns (bool success); + function transferFrom(address from, address to, uint tokens) public returns (bool success); + + event Transfer(address indexed from, address indexed to, uint tokens); + event Approval(address indexed tokenOwner, address indexed spender, uint tokens); +} + + +//Contract function to receive approval and execute function in one call + +contract ApproveAndCallFallBack { + function receiveApproval(address from, uint256 tokens, address token, bytes data) public; +} + +//Actual token contract + +contract PushToken is ERC20Interface, SafeMath { + string public symbol; + string public name; + uint8 public decimals; + uint public _totalSupply; + + mapping(address => uint) balances; + mapping(address => mapping(address => uint)) allowed; + + constructor() public { + symbol = "PUSH"; + name = "Push Token"; + decimals = 2; + _totalSupply = 100000; + balances[msg.sender] = _totalSupply; + emit Transfer(address(0), msg.sender, _totalSupply); + } + + function totalSupply() public constant returns (uint) { + return _totalSupply - balances[address(0)]; + } + + function balanceOf(address tokenOwner) public constant returns (uint balance) { + return balances[tokenOwner]; + } + + function transfer(address to, uint tokens) public returns (bool success) { + balances[msg.sender] = safeSub(balances[msg.sender], tokens); + balances[to] = safeAdd(balances[to], tokens); + emit Transfer(msg.sender, to, tokens); + return true; + } + + function approve(address spender, uint tokens) public returns (bool success) { + allowed[msg.sender][spender] = tokens; + emit Approval(msg.sender, spender, tokens); + return true; + } + + function transferFrom(address from, address to, uint tokens) public returns (bool success) { + balances[from] = safeSub(balances[from], tokens); + allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens); + balances[to] = safeAdd(balances[to], tokens); + emit Transfer(from, to, tokens); + return true; + } + + function allowance(address tokenOwner, address spender) public constant returns (uint remaining) { + return allowed[tokenOwner][spender]; + } + + function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) { + allowed[msg.sender][spender] = tokens; + emit Approval(msg.sender, spender, tokens); + ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data); + return true; + } + + function () public payable { + revert(); + } +} \ No newline at end of file diff --git a/packages/examples/subgraph-notification/generated/PushToken/PushToken.ts b/packages/examples/subgraph-notification/generated/PushToken/PushToken.ts new file mode 100644 index 000000000..080653c32 --- /dev/null +++ b/packages/examples/subgraph-notification/generated/PushToken/PushToken.ts @@ -0,0 +1,619 @@ +// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + +import { + ethereum, + JSONValue, + TypedMap, + Entity, + Bytes, + Address, + BigInt +} from "@graphprotocol/graph-ts"; + +export class Transfer extends ethereum.Event { + get params(): Transfer__Params { + return new Transfer__Params(this); + } +} + +export class Transfer__Params { + _event: Transfer; + + constructor(event: Transfer) { + this._event = event; + } + + get from(): Address { + return this._event.parameters[0].value.toAddress(); + } + + get to(): Address { + return this._event.parameters[1].value.toAddress(); + } + + get tokens(): BigInt { + return this._event.parameters[2].value.toBigInt(); + } +} + +export class Approval extends ethereum.Event { + get params(): Approval__Params { + return new Approval__Params(this); + } +} + +export class Approval__Params { + _event: Approval; + + constructor(event: Approval) { + this._event = event; + } + + get tokenOwner(): Address { + return this._event.parameters[0].value.toAddress(); + } + + get spender(): Address { + return this._event.parameters[1].value.toAddress(); + } + + get tokens(): BigInt { + return this._event.parameters[2].value.toBigInt(); + } +} + +export class PushToken extends ethereum.SmartContract { + static bind(address: Address): PushToken { + return new PushToken("PushToken", address); + } + + name(): string { + let result = super.call("name", "name():(string)", []); + + return result[0].toString(); + } + + try_name(): ethereum.CallResult<string> { + let result = super.tryCall("name", "name():(string)", []); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toString()); + } + + approve(spender: Address, tokens: BigInt): boolean { + let result = super.call("approve", "approve(address,uint256):(bool)", [ + ethereum.Value.fromAddress(spender), + ethereum.Value.fromUnsignedBigInt(tokens) + ]); + + return result[0].toBoolean(); + } + + try_approve(spender: Address, tokens: BigInt): ethereum.CallResult<boolean> { + let result = super.tryCall("approve", "approve(address,uint256):(bool)", [ + ethereum.Value.fromAddress(spender), + ethereum.Value.fromUnsignedBigInt(tokens) + ]); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBoolean()); + } + + totalSupply(): BigInt { + let result = super.call("totalSupply", "totalSupply():(uint256)", []); + + return result[0].toBigInt(); + } + + try_totalSupply(): ethereum.CallResult<BigInt> { + let result = super.tryCall("totalSupply", "totalSupply():(uint256)", []); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBigInt()); + } + + transferFrom(from: Address, to: Address, tokens: BigInt): boolean { + let result = super.call( + "transferFrom", + "transferFrom(address,address,uint256):(bool)", + [ + ethereum.Value.fromAddress(from), + ethereum.Value.fromAddress(to), + ethereum.Value.fromUnsignedBigInt(tokens) + ] + ); + + return result[0].toBoolean(); + } + + try_transferFrom( + from: Address, + to: Address, + tokens: BigInt + ): ethereum.CallResult<boolean> { + let result = super.tryCall( + "transferFrom", + "transferFrom(address,address,uint256):(bool)", + [ + ethereum.Value.fromAddress(from), + ethereum.Value.fromAddress(to), + ethereum.Value.fromUnsignedBigInt(tokens) + ] + ); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBoolean()); + } + + decimals(): i32 { + let result = super.call("decimals", "decimals():(uint8)", []); + + return result[0].toI32(); + } + + try_decimals(): ethereum.CallResult<i32> { + let result = super.tryCall("decimals", "decimals():(uint8)", []); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toI32()); + } + + _totalSupply(): BigInt { + let result = super.call("_totalSupply", "_totalSupply():(uint256)", []); + + return result[0].toBigInt(); + } + + try__totalSupply(): ethereum.CallResult<BigInt> { + let result = super.tryCall("_totalSupply", "_totalSupply():(uint256)", []); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBigInt()); + } + + balanceOf(tokenOwner: Address): BigInt { + let result = super.call("balanceOf", "balanceOf(address):(uint256)", [ + ethereum.Value.fromAddress(tokenOwner) + ]); + + return result[0].toBigInt(); + } + + try_balanceOf(tokenOwner: Address): ethereum.CallResult<BigInt> { + let result = super.tryCall("balanceOf", "balanceOf(address):(uint256)", [ + ethereum.Value.fromAddress(tokenOwner) + ]); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBigInt()); + } + + symbol(): string { + let result = super.call("symbol", "symbol():(string)", []); + + return result[0].toString(); + } + + try_symbol(): ethereum.CallResult<string> { + let result = super.tryCall("symbol", "symbol():(string)", []); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toString()); + } + + safeSub(a: BigInt, b: BigInt): BigInt { + let result = super.call("safeSub", "safeSub(uint256,uint256):(uint256)", [ + ethereum.Value.fromUnsignedBigInt(a), + ethereum.Value.fromUnsignedBigInt(b) + ]); + + return result[0].toBigInt(); + } + + try_safeSub(a: BigInt, b: BigInt): ethereum.CallResult<BigInt> { + let result = super.tryCall( + "safeSub", + "safeSub(uint256,uint256):(uint256)", + [ + ethereum.Value.fromUnsignedBigInt(a), + ethereum.Value.fromUnsignedBigInt(b) + ] + ); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBigInt()); + } + + transfer(to: Address, tokens: BigInt): boolean { + let result = super.call("transfer", "transfer(address,uint256):(bool)", [ + ethereum.Value.fromAddress(to), + ethereum.Value.fromUnsignedBigInt(tokens) + ]); + + return result[0].toBoolean(); + } + + try_transfer(to: Address, tokens: BigInt): ethereum.CallResult<boolean> { + let result = super.tryCall("transfer", "transfer(address,uint256):(bool)", [ + ethereum.Value.fromAddress(to), + ethereum.Value.fromUnsignedBigInt(tokens) + ]); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBoolean()); + } + + safeDiv(a: BigInt, b: BigInt): BigInt { + let result = super.call("safeDiv", "safeDiv(uint256,uint256):(uint256)", [ + ethereum.Value.fromUnsignedBigInt(a), + ethereum.Value.fromUnsignedBigInt(b) + ]); + + return result[0].toBigInt(); + } + + try_safeDiv(a: BigInt, b: BigInt): ethereum.CallResult<BigInt> { + let result = super.tryCall( + "safeDiv", + "safeDiv(uint256,uint256):(uint256)", + [ + ethereum.Value.fromUnsignedBigInt(a), + ethereum.Value.fromUnsignedBigInt(b) + ] + ); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBigInt()); + } + + approveAndCall(spender: Address, tokens: BigInt, data: Bytes): boolean { + let result = super.call( + "approveAndCall", + "approveAndCall(address,uint256,bytes):(bool)", + [ + ethereum.Value.fromAddress(spender), + ethereum.Value.fromUnsignedBigInt(tokens), + ethereum.Value.fromBytes(data) + ] + ); + + return result[0].toBoolean(); + } + + try_approveAndCall( + spender: Address, + tokens: BigInt, + data: Bytes + ): ethereum.CallResult<boolean> { + let result = super.tryCall( + "approveAndCall", + "approveAndCall(address,uint256,bytes):(bool)", + [ + ethereum.Value.fromAddress(spender), + ethereum.Value.fromUnsignedBigInt(tokens), + ethereum.Value.fromBytes(data) + ] + ); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBoolean()); + } + + safeMul(a: BigInt, b: BigInt): BigInt { + let result = super.call("safeMul", "safeMul(uint256,uint256):(uint256)", [ + ethereum.Value.fromUnsignedBigInt(a), + ethereum.Value.fromUnsignedBigInt(b) + ]); + + return result[0].toBigInt(); + } + + try_safeMul(a: BigInt, b: BigInt): ethereum.CallResult<BigInt> { + let result = super.tryCall( + "safeMul", + "safeMul(uint256,uint256):(uint256)", + [ + ethereum.Value.fromUnsignedBigInt(a), + ethereum.Value.fromUnsignedBigInt(b) + ] + ); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBigInt()); + } + + allowance(tokenOwner: Address, spender: Address): BigInt { + let result = super.call( + "allowance", + "allowance(address,address):(uint256)", + [ + ethereum.Value.fromAddress(tokenOwner), + ethereum.Value.fromAddress(spender) + ] + ); + + return result[0].toBigInt(); + } + + try_allowance( + tokenOwner: Address, + spender: Address + ): ethereum.CallResult<BigInt> { + let result = super.tryCall( + "allowance", + "allowance(address,address):(uint256)", + [ + ethereum.Value.fromAddress(tokenOwner), + ethereum.Value.fromAddress(spender) + ] + ); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBigInt()); + } + + safeAdd(a: BigInt, b: BigInt): BigInt { + let result = super.call("safeAdd", "safeAdd(uint256,uint256):(uint256)", [ + ethereum.Value.fromUnsignedBigInt(a), + ethereum.Value.fromUnsignedBigInt(b) + ]); + + return result[0].toBigInt(); + } + + try_safeAdd(a: BigInt, b: BigInt): ethereum.CallResult<BigInt> { + let result = super.tryCall( + "safeAdd", + "safeAdd(uint256,uint256):(uint256)", + [ + ethereum.Value.fromUnsignedBigInt(a), + ethereum.Value.fromUnsignedBigInt(b) + ] + ); + if (result.reverted) { + return new ethereum.CallResult(); + } + let value = result.value; + return ethereum.CallResult.fromValue(value[0].toBigInt()); + } +} + +export class ApproveCall extends ethereum.Call { + get inputs(): ApproveCall__Inputs { + return new ApproveCall__Inputs(this); + } + + get outputs(): ApproveCall__Outputs { + return new ApproveCall__Outputs(this); + } +} + +export class ApproveCall__Inputs { + _call: ApproveCall; + + constructor(call: ApproveCall) { + this._call = call; + } + + get spender(): Address { + return this._call.inputValues[0].value.toAddress(); + } + + get tokens(): BigInt { + return this._call.inputValues[1].value.toBigInt(); + } +} + +export class ApproveCall__Outputs { + _call: ApproveCall; + + constructor(call: ApproveCall) { + this._call = call; + } + + get success(): boolean { + return this._call.outputValues[0].value.toBoolean(); + } +} + +export class TransferFromCall extends ethereum.Call { + get inputs(): TransferFromCall__Inputs { + return new TransferFromCall__Inputs(this); + } + + get outputs(): TransferFromCall__Outputs { + return new TransferFromCall__Outputs(this); + } +} + +export class TransferFromCall__Inputs { + _call: TransferFromCall; + + constructor(call: TransferFromCall) { + this._call = call; + } + + get from(): Address { + return this._call.inputValues[0].value.toAddress(); + } + + get to(): Address { + return this._call.inputValues[1].value.toAddress(); + } + + get tokens(): BigInt { + return this._call.inputValues[2].value.toBigInt(); + } +} + +export class TransferFromCall__Outputs { + _call: TransferFromCall; + + constructor(call: TransferFromCall) { + this._call = call; + } + + get success(): boolean { + return this._call.outputValues[0].value.toBoolean(); + } +} + +export class TransferCall extends ethereum.Call { + get inputs(): TransferCall__Inputs { + return new TransferCall__Inputs(this); + } + + get outputs(): TransferCall__Outputs { + return new TransferCall__Outputs(this); + } +} + +export class TransferCall__Inputs { + _call: TransferCall; + + constructor(call: TransferCall) { + this._call = call; + } + + get to(): Address { + return this._call.inputValues[0].value.toAddress(); + } + + get tokens(): BigInt { + return this._call.inputValues[1].value.toBigInt(); + } +} + +export class TransferCall__Outputs { + _call: TransferCall; + + constructor(call: TransferCall) { + this._call = call; + } + + get success(): boolean { + return this._call.outputValues[0].value.toBoolean(); + } +} + +export class ApproveAndCallCall extends ethereum.Call { + get inputs(): ApproveAndCallCall__Inputs { + return new ApproveAndCallCall__Inputs(this); + } + + get outputs(): ApproveAndCallCall__Outputs { + return new ApproveAndCallCall__Outputs(this); + } +} + +export class ApproveAndCallCall__Inputs { + _call: ApproveAndCallCall; + + constructor(call: ApproveAndCallCall) { + this._call = call; + } + + get spender(): Address { + return this._call.inputValues[0].value.toAddress(); + } + + get tokens(): BigInt { + return this._call.inputValues[1].value.toBigInt(); + } + + get data(): Bytes { + return this._call.inputValues[2].value.toBytes(); + } +} + +export class ApproveAndCallCall__Outputs { + _call: ApproveAndCallCall; + + constructor(call: ApproveAndCallCall) { + this._call = call; + } + + get success(): boolean { + return this._call.outputValues[0].value.toBoolean(); + } +} + +export class ConstructorCall extends ethereum.Call { + get inputs(): ConstructorCall__Inputs { + return new ConstructorCall__Inputs(this); + } + + get outputs(): ConstructorCall__Outputs { + return new ConstructorCall__Outputs(this); + } +} + +export class ConstructorCall__Inputs { + _call: ConstructorCall; + + constructor(call: ConstructorCall) { + this._call = call; + } +} + +export class ConstructorCall__Outputs { + _call: ConstructorCall; + + constructor(call: ConstructorCall) { + this._call = call; + } +} + +export class DefaultCall extends ethereum.Call { + get inputs(): DefaultCall__Inputs { + return new DefaultCall__Inputs(this); + } + + get outputs(): DefaultCall__Outputs { + return new DefaultCall__Outputs(this); + } +} + +export class DefaultCall__Inputs { + _call: DefaultCall; + + constructor(call: DefaultCall) { + this._call = call; + } +} + +export class DefaultCall__Outputs { + _call: DefaultCall; + + constructor(call: DefaultCall) { + this._call = call; + } +} diff --git a/packages/examples/subgraph-notification/generated/schema.ts b/packages/examples/subgraph-notification/generated/schema.ts new file mode 100644 index 000000000..71b007f31 --- /dev/null +++ b/packages/examples/subgraph-notification/generated/schema.ts @@ -0,0 +1,428 @@ +// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + +import { + TypedMap, + Entity, + Value, + ValueKind, + store, + Bytes, + BigInt, + BigDecimal +} from "@graphprotocol/graph-ts"; + +export class User extends Entity { + constructor(id: string) { + super(); + this.set("id", Value.fromString(id)); + } + + save(): void { + let id = this.get("id"); + assert(id != null, "Cannot save User entity without an ID"); + if (id) { + assert( + id.kind == ValueKind.STRING, + `Entities of type User must have an ID of type String but the id '${id.displayData()}' is of type ${id.displayKind()}` + ); + store.set("User", id.toString(), this); + } + } + + static load(id: string): User | null { + return changetype<User | null>(store.get("User", id)); + } + + get id(): string { + let value = this.get("id"); + return value!.toString(); + } + + set id(value: string) { + this.set("id", Value.fromString(value)); + } + + get address(): string { + let value = this.get("address"); + return value!.toString(); + } + + set address(value: string) { + this.set("address", Value.fromString(value)); + } + + get balance(): BigInt { + let value = this.get("balance"); + return value!.toBigInt(); + } + + set balance(value: BigInt) { + this.set("balance", Value.fromBigInt(value)); + } + + get transactionCount(): i32 { + let value = this.get("transactionCount"); + return value!.toI32(); + } + + set transactionCount(value: i32) { + this.set("transactionCount", Value.fromI32(value)); + } +} + +export class Minter extends Entity { + constructor(id: string) { + super(); + this.set("id", Value.fromString(id)); + } + + save(): void { + let id = this.get("id"); + assert(id != null, "Cannot save Minter entity without an ID"); + if (id) { + assert( + id.kind == ValueKind.STRING, + `Entities of type Minter must have an ID of type String but the id '${id.displayData()}' is of type ${id.displayKind()}` + ); + store.set("Minter", id.toString(), this); + } + } + + static load(id: string): Minter | null { + return changetype<Minter | null>(store.get("Minter", id)); + } + + get id(): string { + let value = this.get("id"); + return value!.toString(); + } + + set id(value: string) { + this.set("id", Value.fromString(value)); + } + + get address(): string { + let value = this.get("address"); + return value!.toString(); + } + + set address(value: string) { + this.set("address", Value.fromString(value)); + } + + get totalMinted(): BigInt { + let value = this.get("totalMinted"); + return value!.toBigInt(); + } + + set totalMinted(value: BigInt) { + this.set("totalMinted", Value.fromBigInt(value)); + } + + get totalBurned(): BigInt { + let value = this.get("totalBurned"); + return value!.toBigInt(); + } + + set totalBurned(value: BigInt) { + this.set("totalBurned", Value.fromBigInt(value)); + } +} + +export class UserCounter extends Entity { + constructor(id: string) { + super(); + this.set("id", Value.fromString(id)); + } + + save(): void { + let id = this.get("id"); + assert(id != null, "Cannot save UserCounter entity without an ID"); + if (id) { + assert( + id.kind == ValueKind.STRING, + `Entities of type UserCounter must have an ID of type String but the id '${id.displayData()}' is of type ${id.displayKind()}` + ); + store.set("UserCounter", id.toString(), this); + } + } + + static load(id: string): UserCounter | null { + return changetype<UserCounter | null>(store.get("UserCounter", id)); + } + + get id(): string { + let value = this.get("id"); + return value!.toString(); + } + + set id(value: string) { + this.set("id", Value.fromString(value)); + } + + get count(): i32 { + let value = this.get("count"); + return value!.toI32(); + } + + set count(value: i32) { + this.set("count", Value.fromI32(value)); + } +} + +export class MinterCounter extends Entity { + constructor(id: string) { + super(); + this.set("id", Value.fromString(id)); + } + + save(): void { + let id = this.get("id"); + assert(id != null, "Cannot save MinterCounter entity without an ID"); + if (id) { + assert( + id.kind == ValueKind.STRING, + `Entities of type MinterCounter must have an ID of type String but the id '${id.displayData()}' is of type ${id.displayKind()}` + ); + store.set("MinterCounter", id.toString(), this); + } + } + + static load(id: string): MinterCounter | null { + return changetype<MinterCounter | null>(store.get("MinterCounter", id)); + } + + get id(): string { + let value = this.get("id"); + return value!.toString(); + } + + set id(value: string) { + this.set("id", Value.fromString(value)); + } + + get count(): i32 { + let value = this.get("count"); + return value!.toI32(); + } + + set count(value: i32) { + this.set("count", Value.fromI32(value)); + } +} + +export class TransferCounter extends Entity { + constructor(id: string) { + super(); + this.set("id", Value.fromString(id)); + } + + save(): void { + let id = this.get("id"); + assert(id != null, "Cannot save TransferCounter entity without an ID"); + if (id) { + assert( + id.kind == ValueKind.STRING, + `Entities of type TransferCounter must have an ID of type String but the id '${id.displayData()}' is of type ${id.displayKind()}` + ); + store.set("TransferCounter", id.toString(), this); + } + } + + static load(id: string): TransferCounter | null { + return changetype<TransferCounter | null>(store.get("TransferCounter", id)); + } + + get id(): string { + let value = this.get("id"); + return value!.toString(); + } + + set id(value: string) { + this.set("id", Value.fromString(value)); + } + + get count(): i32 { + let value = this.get("count"); + return value!.toI32(); + } + + set count(value: i32) { + this.set("count", Value.fromI32(value)); + } + + get totalTransferred(): BigInt { + let value = this.get("totalTransferred"); + return value!.toBigInt(); + } + + set totalTransferred(value: BigInt) { + this.set("totalTransferred", Value.fromBigInt(value)); + } +} + +export class TotalSupply extends Entity { + constructor(id: string) { + super(); + this.set("id", Value.fromString(id)); + } + + save(): void { + let id = this.get("id"); + assert(id != null, "Cannot save TotalSupply entity without an ID"); + if (id) { + assert( + id.kind == ValueKind.STRING, + `Entities of type TotalSupply must have an ID of type String but the id '${id.displayData()}' is of type ${id.displayKind()}` + ); + store.set("TotalSupply", id.toString(), this); + } + } + + static load(id: string): TotalSupply | null { + return changetype<TotalSupply | null>(store.get("TotalSupply", id)); + } + + get id(): string { + let value = this.get("id"); + return value!.toString(); + } + + set id(value: string) { + this.set("id", Value.fromString(value)); + } + + get supply(): BigInt { + let value = this.get("supply"); + return value!.toBigInt(); + } + + set supply(value: BigInt) { + this.set("supply", Value.fromBigInt(value)); + } + + get minted(): BigInt { + let value = this.get("minted"); + return value!.toBigInt(); + } + + set minted(value: BigInt) { + this.set("minted", Value.fromBigInt(value)); + } + + get burned(): BigInt { + let value = this.get("burned"); + return value!.toBigInt(); + } + + set burned(value: BigInt) { + this.set("burned", Value.fromBigInt(value)); + } +} + +export class EpnsNotificationCounter extends Entity { + constructor(id: string) { + super(); + this.set("id", Value.fromString(id)); + } + + save(): void { + let id = this.get("id"); + assert( + id != null, + "Cannot save EpnsNotificationCounter entity without an ID" + ); + if (id) { + assert( + id.kind == ValueKind.STRING, + `Entities of type EpnsNotificationCounter must have an ID of type String but the id '${id.displayData()}' is of type ${id.displayKind()}` + ); + store.set("EpnsNotificationCounter", id.toString(), this); + } + } + + static load(id: string): EpnsNotificationCounter | null { + return changetype<EpnsNotificationCounter | null>( + store.get("EpnsNotificationCounter", id) + ); + } + + get id(): string { + let value = this.get("id"); + return value!.toString(); + } + + set id(value: string) { + this.set("id", Value.fromString(value)); + } + + get totalCount(): BigInt { + let value = this.get("totalCount"); + return value!.toBigInt(); + } + + set totalCount(value: BigInt) { + this.set("totalCount", Value.fromBigInt(value)); + } +} + +export class EpnsPushNotification extends Entity { + constructor(id: string) { + super(); + this.set("id", Value.fromString(id)); + } + + save(): void { + let id = this.get("id"); + assert(id != null, "Cannot save EpnsPushNotification entity without an ID"); + if (id) { + assert( + id.kind == ValueKind.STRING, + `Entities of type EpnsPushNotification must have an ID of type String but the id '${id.displayData()}' is of type ${id.displayKind()}` + ); + store.set("EpnsPushNotification", id.toString(), this); + } + } + + static load(id: string): EpnsPushNotification | null { + return changetype<EpnsPushNotification | null>( + store.get("EpnsPushNotification", id) + ); + } + + get id(): string { + let value = this.get("id"); + return value!.toString(); + } + + set id(value: string) { + this.set("id", Value.fromString(value)); + } + + get notificationNumber(): BigInt { + let value = this.get("notificationNumber"); + return value!.toBigInt(); + } + + set notificationNumber(value: BigInt) { + this.set("notificationNumber", Value.fromBigInt(value)); + } + + get recipient(): string { + let value = this.get("recipient"); + return value!.toString(); + } + + set recipient(value: string) { + this.set("recipient", Value.fromString(value)); + } + + get notification(): string { + let value = this.get("notification"); + return value!.toString(); + } + + set notification(value: string) { + this.set("notification", Value.fromString(value)); + } +} diff --git a/packages/examples/subgraph-notification/networks.json b/packages/examples/subgraph-notification/networks.json new file mode 100644 index 000000000..4b22acd17 --- /dev/null +++ b/packages/examples/subgraph-notification/networks.json @@ -0,0 +1,7 @@ +{ + "goerli": { + "EPNSCore": { + "address": "0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C" + } + } +} \ No newline at end of file diff --git a/packages/examples/subgraph-notification/package.json b/packages/examples/subgraph-notification/package.json new file mode 100644 index 000000000..7a3236c12 --- /dev/null +++ b/packages/examples/subgraph-notification/package.json @@ -0,0 +1,18 @@ +{ + "name": "push-graph-test", + "license": "UNLICENSED", + "scripts": { + "codegen": "graph codegen", + "build": "graph build", + "deploy": "graph deploy --node https://api.studio.thegraph.com/deploy/ aiswaryawalter/push-graph-test", + "create-local": "graph create --node http://localhost:8020/ aiswaryawalter/push-graph-test", + "remove-local": "graph remove --node http://localhost:8020/ aiswaryawalter/push-graph-test", + "deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 aiswaryawalter/push-graph-test", + "test": "graph test" + }, + "dependencies": { + "@graphprotocol/graph-cli": "0.34.0", + "@graphprotocol/graph-ts": "0.28.0" + }, + "devDependencies": { "matchstick-as": "0.5.0" } +} diff --git a/packages/examples/subgraph-notification/schema.graphql b/packages/examples/subgraph-notification/schema.graphql new file mode 100644 index 000000000..4114b9d84 --- /dev/null +++ b/packages/examples/subgraph-notification/schema.graphql @@ -0,0 +1,49 @@ +type User @entity { + id: ID! + address: String! + balance: BigInt! + transactionCount: Int! +} + +type Minter @entity { + id: ID! + address: String! + totalMinted: BigInt! + totalBurned: BigInt! +} + +type UserCounter @entity { + id: ID! + count: Int! +} + +type MinterCounter @entity { + id: ID! + count: Int! +} + +type TransferCounter @entity { + id: ID! + count: Int! + totalTransferred: BigInt! +} + +type TotalSupply @entity { + id: ID! + supply: BigInt! + minted: BigInt! + burned: BigInt! +} + +type EpnsNotificationCounter @entity { + id: ID! + totalCount: BigInt! +} + +type EpnsPushNotification @entity { + id: ID! + notificationNumber: BigInt! + recipient: String! + notification: String! +} + diff --git a/packages/examples/subgraph-notification/src/PushNotification.ts b/packages/examples/subgraph-notification/src/PushNotification.ts new file mode 100644 index 000000000..61a387b1a --- /dev/null +++ b/packages/examples/subgraph-notification/src/PushNotification.ts @@ -0,0 +1,30 @@ +import { + BigInt, + log } from "@graphprotocol/graph-ts" +import { EpnsNotificationCounter, EpnsPushNotification } from '../generated/schema' +import { subgraphID } from "./push-token" + +export function sendPushNotification(recipient: string, notification: string): void +{ + let id1 = subgraphID + log.info('New id of EpnsNotificationCounter is: {}', [id1]) + let epnsNotificationCounter = EpnsNotificationCounter.load(id1) + if (epnsNotificationCounter == null) { + epnsNotificationCounter = new EpnsNotificationCounter(id1) + epnsNotificationCounter.totalCount = BigInt.fromI32(0) + } + epnsNotificationCounter.totalCount = (epnsNotificationCounter.totalCount).plus(BigInt.fromI32(1)) + + let count = epnsNotificationCounter.totalCount.toHexString() + let id2 = `${subgraphID}+${count}` + log.info('New id of EpnsPushNotification is: {}', [id2]) + let epnsPushNotification = EpnsPushNotification.load(id2) + if (epnsPushNotification == null) { + epnsPushNotification = new EpnsPushNotification(id2) + } + epnsPushNotification.recipient = recipient + epnsPushNotification.notification = notification + epnsPushNotification.notificationNumber = epnsNotificationCounter.totalCount + epnsPushNotification.save() + epnsNotificationCounter.save() +} \ No newline at end of file diff --git a/packages/examples/subgraph-notification/src/push-token.ts b/packages/examples/subgraph-notification/src/push-token.ts new file mode 100644 index 000000000..c66216cda --- /dev/null +++ b/packages/examples/subgraph-notification/src/push-token.ts @@ -0,0 +1,90 @@ +import { BigInt } from "@graphprotocol/graph-ts" +import { PushToken, Transfer, Approval } from "../generated/PushToken/PushToken" +import { User, UserCounter, TransferCounter } from "../generated/schema" +import { sendPushNotification } from "./PushNotification" +export const subgraphID = "aiswaryawalter/push-protocol-goerli" + +let ZERO_BI = BigInt.fromI32(0) +let ONE_BI = BigInt.fromI32(1) + +export function handleTransfer(event: Transfer): void { + let contract = PushToken.bind(event.address) + let decimals = BigInt.fromString(contract.decimals().toString()) + let power = exponentToBigInt(decimals) + let day = (event.block.timestamp.div(BigInt.fromI32(60 * 60 * 24))) + + let userFrom = User.load(event.params.from.toHex()) + if (userFrom == null) { + userFrom = newUser(event.params.from.toHex(), event.params.from.toHex()); + } + userFrom.balance = (userFrom.balance).minus(event.params.tokens) + userFrom.transactionCount = userFrom.transactionCount + 1 + userFrom.save() + + let userTo = User.load(event.params.to.toHex()) + if (userTo == null) { + userTo = newUser(event.params.to.toHex(), event.params.to.toHex()); + + // UserCounter + let userCounter = UserCounter.load('singleton') + if (userCounter == null) { + userCounter = new UserCounter('singleton') + userCounter.count = 1 + } else { + userCounter.count = userCounter.count + 1 + } + userCounter.save() + userCounter.id = day.toString() + userCounter.save() + } + userTo.balance = (userTo.balance).plus(event.params.tokens) + userTo.transactionCount = userTo.transactionCount + 1 + userTo.save() + + // Transfer counter total and historical + let transferCounter = TransferCounter.load('singleton') + if (transferCounter == null) { + transferCounter = new TransferCounter('singleton') + transferCounter.count = 0 + transferCounter.totalTransferred = BigInt.fromI32(0) + } + transferCounter.count = transferCounter.count + 1 + transferCounter.totalTransferred = transferCounter.totalTransferred.plus(event.params.tokens) + transferCounter.save() + transferCounter.id = day.toString() + transferCounter.save() + + let recipient = event.params.to.toHexString(), + type = "3", + title = "PUSH Received", + body = `Received ${event.params.tokens.div(power)} PUSH from ${event.params.from.toHexString()}`, + subject = "PUSH Received", + message = `Received ${event.params.tokens.div(power)} PUSH from ${event.params.from.toHexString()}`, + image = "https://play-lh.googleusercontent.com/i911_wMmFilaAAOTLvlQJZMXoxBF34BMSzRmascHezvurtslYUgOHamxgEnMXTklsF-S", + secret = "null", + cta = "https://epns.io/", + + notification = `{\"type\": \"${type}\", \"title\": \"${title}\", \"body\": \"${body}\", \"subject\": \"${subject}\", \"message\": \"${message}\", \"image\": \"${image}\", \"secret\": \"${secret}\", \"cta\": \"${cta}\"}` + + sendPushNotification( + recipient, + notification + ) +} + +function newUser(id: string, address: string): User { + let user = new User(id); + user.address = address + user.balance = BigInt.fromI32(0) + user.transactionCount = 0 + return user +} +function exponentToBigInt(decimals: BigInt): BigInt { + let bd = BigInt.fromString('1') + for (let i = ZERO_BI; i.lt(decimals as BigInt); i = i.plus(ONE_BI)) { + bd = bd.times(BigInt.fromString('10')) + } + return bd +} + +// export function handleApproval(event: Approval): void {} diff --git a/packages/examples/subgraph-notification/subgraph.yaml b/packages/examples/subgraph-notification/subgraph.yaml new file mode 100644 index 000000000..94e3702ae --- /dev/null +++ b/packages/examples/subgraph-notification/subgraph.yaml @@ -0,0 +1,27 @@ +specVersion: 0.0.4 +schema: + file: ./schema.graphql +dataSources: + - kind: ethereum + name: PushToken + network: goerli + source: + address: "0x9120041585424b7c830f7A0b2DC3245da019a4BF" + abi: PushToken + startBlock: 7750861 + mapping: + kind: ethereum/events + apiVersion: 0.0.6 + language: wasm/assemblyscript + entities: + - Transfer + - Approval + abis: + - name: PushToken + file: ./abis/PushToken.json + eventHandlers: + - event: Transfer(indexed address,indexed address,uint256) + handler: handleTransfer + - event: Approval(indexed address,indexed address,uint256) + handler: handleApproval + file: ./src/push-token.ts diff --git a/packages/examples/subgraph-notification/tests/epns-core-utils.ts b/packages/examples/subgraph-notification/tests/epns-core-utils.ts new file mode 100644 index 000000000..267d00259 --- /dev/null +++ b/packages/examples/subgraph-notification/tests/epns-core-utils.ts @@ -0,0 +1,39 @@ +import { newMockEvent } from "matchstick-as" +import { ethereum, Address } from "@graphprotocol/graph-ts" +import { AdminChanged, Upgraded } from "../generated/EPNSCore/EPNSCore" + +export function createAdminChangedEvent( + previousAdmin: Address, + newAdmin: Address +): AdminChanged { + let adminChangedEvent = changetype<AdminChanged>(newMockEvent()) + + adminChangedEvent.parameters = new Array() + + adminChangedEvent.parameters.push( + new ethereum.EventParam( + "previousAdmin", + ethereum.Value.fromAddress(previousAdmin) + ) + ) + adminChangedEvent.parameters.push( + new ethereum.EventParam("newAdmin", ethereum.Value.fromAddress(newAdmin)) + ) + + return adminChangedEvent +} + +export function createUpgradedEvent(implementation: Address): Upgraded { + let upgradedEvent = changetype<Upgraded>(newMockEvent()) + + upgradedEvent.parameters = new Array() + + upgradedEvent.parameters.push( + new ethereum.EventParam( + "implementation", + ethereum.Value.fromAddress(implementation) + ) + ) + + return upgradedEvent +} diff --git a/packages/examples/subgraph-notification/tests/epns-core.test.ts b/packages/examples/subgraph-notification/tests/epns-core.test.ts new file mode 100644 index 000000000..3dc4b3183 --- /dev/null +++ b/packages/examples/subgraph-notification/tests/epns-core.test.ts @@ -0,0 +1,57 @@ +import { + assert, + describe, + test, + clearStore, + beforeAll, + afterAll +} from "matchstick-as/assembly/index" +import { Address } from "@graphprotocol/graph-ts" +import { ExampleEntity } from "../generated/schema" +import { AdminChanged } from "../generated/EPNSCore/EPNSCore" +import { handleAdminChanged } from "../src/epns-core" +import { createAdminChangedEvent } from "./epns-core-utils" + +// Tests structure (matchstick-as >=0.5.0) +// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 + +describe("Describe entity assertions", () => { + beforeAll(() => { + let previousAdmin = Address.fromString( + "0x0000000000000000000000000000000000000001" + ) + let newAdmin = Address.fromString( + "0x0000000000000000000000000000000000000001" + ) + let newAdminChangedEvent = createAdminChangedEvent(previousAdmin, newAdmin) + handleAdminChanged(newAdminChangedEvent) + }) + + afterAll(() => { + clearStore() + }) + + // For more test scenarios, see: + // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test + + test("ExampleEntity created and stored", () => { + assert.entityCount("ExampleEntity", 1) + + // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function + assert.fieldEquals( + "ExampleEntity", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a", + "previousAdmin", + "0x0000000000000000000000000000000000000001" + ) + assert.fieldEquals( + "ExampleEntity", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a", + "newAdmin", + "0x0000000000000000000000000000000000000001" + ) + + // More assert options: + // https://thegraph.com/docs/en/developer/matchstick/#asserts + }) +}) diff --git a/packages/examples/subgraph-notification/tsconfig.json b/packages/examples/subgraph-notification/tsconfig.json new file mode 100644 index 000000000..5c5d17c92 --- /dev/null +++ b/packages/examples/subgraph-notification/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@graphprotocol/graph-ts/types/tsconfig.base.json", + "include": ["src"] +} diff --git a/packages/examples/token-gated-chat/README.md b/packages/examples/token-gated-chat/README.md new file mode 100644 index 000000000..e0316899d --- /dev/null +++ b/packages/examples/token-gated-chat/README.md @@ -0,0 +1,13 @@ +# About Token Gated Chat +Token gated chat shows you how to create group chats using Push Chat that can gated in various ways including token or NFT gating on entry of the group or when a participant of that group wants to send a message + +## What's the use case +You can use this example to see the functionality of token gating. Some use cases are: + +- Creating your token gated community and hosting that particular chat on your frontend +- Enabling more token use cases and ensuring that conversations that happen in your group are coming from token holders or from participants that have certain on-chain traits (for example: POAPs, ENS domain names, UD domain names, tec) + +## Install instructions +1. Navigate to this directory from the terminal +2. do `npm install` or `yarn install` +3. do `yarn start` \ No newline at end of file diff --git a/packages/examples/token-gated-chat/index.js b/packages/examples/token-gated-chat/index.js new file mode 100644 index 000000000..4deab4fb0 --- /dev/null +++ b/packages/examples/token-gated-chat/index.js @@ -0,0 +1,59 @@ +import { PushAPI } from '@pushprotocol/restapi'; +import { ethers } from 'ethers'; + +// Creating a random signer from a wallet, ideally this is the wallet you will connect +const signer = ethers.Wallet.createRandom(); + +console.log(`Signer address: ${signer.address} | Signer private key: ${signer.privateKey}`); + +// Initialize wallet user, pass 'prod' instead of 'staging' for mainnet apps +const userAlice = await PushAPI.initialize(signer, { env: 'staging' }); + +// Creating your token gated community +const createTokenGatedGroup = await userAlice.chat.group.create('Push Community', { + description: 'Token gated web3 native chat example', // provide short description of group + image: 'data:image/png;base64,iVBORw0K...', // provide base64 encoded image + members: [], // not needed, rules define this, can omit + admins: [], // not needed as per problem statement, can omit + private: true, + rules: { + "entry": { // entry is based on conditions + "conditions": { + "any": [ // any of the decider should allow entry + { // decider 1 - If admin or owner invites someone + "any": [ + { // criteria 1 + "type": "PUSH", + "category": "INVITE", + "subcategory": "DEFAULT", + "data": { + "inviterRoles": [ + "ADMIN", + "OWNER" + ] + } + } + ] + }, + { // decicder 2 - If wallet holds 1 NFT on polygon testnet + "any": [ + { // criteria 1 + type: "PUSH", // define type that rules engine should go for + category: "ERC721", // define it's ERC20 token that you want to check, supports ERC721 as well + subcategory: "holder", // define if you are checking 'holder' + data: { + "contract": "eip155:80001:0x9105D95577575116948F5afcF479254f49F27939", + "comparison": ">=", // what comparison needs to pass + "amount": 1, // amount that needs to passed + "decimals": 18, + } + } + ] + } + ] + } + } + } +}); + +console.log("Chat created successfully!", createTokenGatedGroup); diff --git a/packages/examples/use-cases/automated-chat/package-lock.json b/packages/examples/token-gated-chat/package-lock.json similarity index 100% rename from packages/examples/use-cases/automated-chat/package-lock.json rename to packages/examples/token-gated-chat/package-lock.json diff --git a/packages/examples/use-cases/automated-chat/package.json b/packages/examples/token-gated-chat/package.json similarity index 54% rename from packages/examples/use-cases/automated-chat/package.json rename to packages/examples/token-gated-chat/package.json index dbd298c44..1333c7602 100644 --- a/packages/examples/use-cases/automated-chat/package.json +++ b/packages/examples/token-gated-chat/package.json @@ -1,20 +1,20 @@ { - "name": "automated-chat", + "name": "token-gated-chat", "version": "1.0.0", - "description": "Example of Push Chat from backend, auto-responding to messages sent", - "main": "src/index.js", + "description": "Example of Push Chat token gated group in action", + "main": "index.js", "type": "module", "scripts": { "build": "rimraf ./build && tsc", "start": "nodemon", - "inspect": "nodemon --inspect src/index.js", - "dev": "node-dev --respawn --transpile-only src/index.js", + "inspect": "nodemon --inspect index.js", + "dev": "node-dev --respawn --transpile-only index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { - "@pushprotocol/restapi": "1.4.19", + "@pushprotocol/restapi": "latest", "@pushprotocol/socket": "0.5.2", "ethers": "5.7.2" }, diff --git a/packages/examples/use-cases/.DONNOTREMOVE b/packages/examples/use-cases/.DONNOTREMOVE deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/examples/use-cases/automated-chat/src/index.js b/packages/examples/use-cases/automated-chat/src/index.js deleted file mode 100644 index 5725040e8..000000000 --- a/packages/examples/use-cases/automated-chat/src/index.js +++ /dev/null @@ -1,42 +0,0 @@ -console.log('Hello World'); - -import { PushAPI } from '@pushprotocol/restapi'; -import { createSocketConnection, EVENTS } from '@pushprotocol/socket'; -import { ethers } from 'ethers'; - -// Creating a random signer from a wallet, ideally this is the wallet you will connect -const signer = ethers.Wallet.createRandom(); - -// Initialize wallet user, pass 'prod' instead of 'staging' for mainnet apps -const userAlice = await PushAPI.initialize(signer, { env: 'prod' }); - -// This will be the wallet address of the recipient -const pushAIWalletAddress = '0x99A08ac6254dcf7ccc37CeC662aeba8eFA666666'; - -// Send a message to Bob -console.log('sending message to PushAI Bot'); -const aliceMessagesPushAI = await userAlice.chat.send(pushAIWalletAddress, { - content: "Gm gm! It's a me... Mario", -}); - -// Create Socket to Listen to incoming messages -const pushSDKSocket = await createSocketConnection({ - user: signer.address, - socketType: 'chat', - socketOptions: { autoConnect: true, reconnectionAttempts: 3 }, - env: 'prod', -}); - -pushSDKSocket.on(EVENTS.CONNECT, (message) => { - console.log('Socket Connected'); -}); - -// React to message payload getting recieved -pushSDKSocket.on(EVENTS.CHAT_RECEIVED_MESSAGE, (message) => { - console.log(message); - pushSDKSocket.disconnect(); -}); - -pushSDKSocket.on(EVENTS.DISCONNECT, (message) => { - console.log('Socket Disconnected'); -}); diff --git a/packages/reactnative/.babelrc b/packages/reactnative/.babelrc deleted file mode 100644 index 677d99a4c..000000000 --- a/packages/reactnative/.babelrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "presets": [ - [ - "@nrwl/react/babel", - { - "runtime": "automatic", - "useBuiltIns": "usage" - } - ] - ] -} \ No newline at end of file diff --git a/packages/reactnative/.editorconfig b/packages/reactnative/.editorconfig new file mode 100644 index 000000000..65365be68 --- /dev/null +++ b/packages/reactnative/.editorconfig @@ -0,0 +1,15 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] + +indent_style = space +indent_size = 2 + +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/packages/reactnative/.eslintrc.json b/packages/reactnative/.eslintrc.json deleted file mode 100644 index ba6f759dd..000000000 --- a/packages/reactnative/.eslintrc.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*", "public", ".cache", "node_modules"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": { - "@typescript-eslint/ban-ts-comment": "off" - } - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/packages/reactnative/.gitattributes b/packages/reactnative/.gitattributes new file mode 100644 index 000000000..030ef1448 --- /dev/null +++ b/packages/reactnative/.gitattributes @@ -0,0 +1,3 @@ +*.pbxproj -text +# specific for windows script files +*.bat text eol=crlf \ No newline at end of file diff --git a/packages/reactnative/.gitignore b/packages/reactnative/.gitignore new file mode 100644 index 000000000..75356714f --- /dev/null +++ b/packages/reactnative/.gitignore @@ -0,0 +1,70 @@ +# OSX +# +.DS_Store + +# XDE +.expo/ + +# VSCode +.vscode/ +jsconfig.json + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# Android/IJ +# +.classpath +.cxx +.gradle +.idea +.project +.settings +local.properties +android.iml + +# Cocoapods +# +example/ios/Pods + +# Ruby +example/vendor/ + +# node.js +# +node_modules/ +npm-debug.log +yarn-debug.log +yarn-error.log + +# BUCK +buck-out/ +\.buckd/ +android/app/libs +android/keystores/debug.keystore + +# Expo +.expo/ + +# Turborepo +.turbo/ + +# generated by bob +lib/ diff --git a/packages/reactnative/.nvmrc b/packages/reactnative/.nvmrc new file mode 100644 index 000000000..5397c87fa --- /dev/null +++ b/packages/reactnative/.nvmrc @@ -0,0 +1 @@ +16.18.1 diff --git a/packages/reactnative/.watchmanconfig b/packages/reactnative/.watchmanconfig new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/packages/reactnative/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/reactnative/.yarnrc b/packages/reactnative/.yarnrc new file mode 100644 index 000000000..fedc0f117 --- /dev/null +++ b/packages/reactnative/.yarnrc @@ -0,0 +1,3 @@ +# Override Yarn command so we can automatically setup the repo on running `yarn` + +yarn-path "scripts/bootstrap.js" diff --git a/packages/reactnative/CHANGELOG.md b/packages/reactnative/CHANGELOG.md deleted file mode 100644 index 96a81f32b..000000000 --- a/packages/reactnative/CHANGELOG.md +++ /dev/null @@ -1,32 +0,0 @@ -# Changelog - -This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver). - -# [0.2.0](https://github.com/ethereum-push-notification-service/push-sdk/compare/reactnative-0.1.0...reactnative-0.2.0) (2023-01-13) - - -### Features - -* Bsc chain config changes added ([#113](https://github.com/ethereum-push-notification-service/push-sdk/issues/113)) ([e1af11b](https://github.com/ethereum-push-notification-service/push-sdk/commit/e1af11b1fa444e30f8aa08ee6b54a30bb03d6070)) - - - -# [0.1.0](https://github.com/ethereum-push-notification-service/sdk/compare/reactnative-0.0.2...reactnative-0.1.0) (2022-10-07) - - -### Features - -* **reactnative:** stable 0.1.0 ([fbcaac1](https://github.com/ethereum-push-notification-service/sdk/commit/fbcaac12df32935d798903bbafafd9e41a6553b6)) - - - -## [0.0.2](https://github.com/ethereum-push-notification-service/sdk/compare/reactnative-0.0.1...reactnative-0.0.2) (2022-10-07) - - -### Bug Fixes - -* **reactnative:** docs update ([fb39df9](https://github.com/ethereum-push-notification-service/sdk/commit/fb39df9d37cf960bc1498f9f51189221a6d52271)) - - - -## 0.0.1 (2022-10-07) diff --git a/packages/reactnative/README.md b/packages/reactnative/README.md index d3e665c64..f0d3d9f26 100644 --- a/packages/reactnative/README.md +++ b/packages/reactnative/README.md @@ -1,212 +1,8 @@ -# reactnative +# @push/react-native-sdk +PUSH -Package for React Native Views for React Native based mobile apps. +## Installation -## How to use in your Mobile app? - -### Installation -``` - yarn add @pushprotocol/reactnative -``` - or -``` - npm install @pushprotocol/reactnative -``` - -### **Please read this carefullly** - -We need to install peer dependencies for `@pushprotocol/reactnative` in your mobile app. And have it set up as below to make it run. - -``` -yarn add @react-native-masked-view/masked-view react-native-svg react-native-video react-native-youtube -``` -Then for different types of react native apps use the below instructions. -### FOR EXPO APPS -``` -expo install expo-file-system -expo install expo-linear-gradient -``` - -### Running IOS -``` -cd ios && pod install -``` -``` -yarn ios -``` - -#### [ViewPropTypes Error](https://github.com/facebook/react-native/issues/33734#issuecomment-1190506381) - -If only you get below error -``` -Invariant Violation: ViewPropTypes has been removed from React Native. Migrate to ViewPropTypes exported from 'deprecated-react-native-prop-types' -``` - -#### ViewPropTypes Error Fix -1. In `node_modules/react-native/index.js` -Replace the below code -``` -// Deprecated Prop Types -get ColorPropType(): $FlowFixMe { - invariant( - false, - "ColorPropType has been removed from React Native. Migrate to " + - "ColorPropType exported from 'deprecated-react-native-prop-types'.", - ); -}, -get EdgeInsetsPropType(): $FlowFixMe { - invariant( - false, - "EdgeInsetsPropType has been removed from React Native. Migrate to " + - "EdgeInsetsPropType exported from 'deprecated-react-native-prop-types'.", - ); -}, -get PointPropType(): $FlowFixMe { - invariant( - false, - "PointPropType has been removed from React Native. Migrate to " + - "PointPropType exported from 'deprecated-react-native-prop-types'.", - ); -}, -get ViewPropTypes(): $FlowFixMe { - invariant( - false, - "ViewPropTypes has been removed from React Native. Migrate to " + - "ViewPropTypes exported from 'deprecated-react-native-prop-types'.", - ); -}, -``` -with below snippet -``` -// Deprecated Prop Types -get ColorPropType(): $FlowFixMe { - return require("deprecated-react-native-prop-types").ColorPropType -}, -get EdgeInsetsPropType(): $FlowFixMe { - return require("deprecated-react-native-prop-types").EdgeInsetsPropType -}, -get PointPropType(): $FlowFixMe { - return require("deprecated-react-native-prop-types").PointPropType -}, -get ViewPropTypes(): $FlowFixMe { - return require("deprecated-react-native-prop-types").ViewPropTypes -}, -``` - -2. `yarn add -D patch-package` -3. `yarn patch-package react-native` -4. `cd ios && pod install` -5. `yarn ios` - -#### [Image.propTypes.resizeMode error](https://github.com/react-native-video/react-native-video/issues/2714) -``` -ERROR TypeError: undefined is not an object (evaluating '_reactNative.Image.propTypes.resizeMode') -``` -then use this -#### [Image.propTypes fix](https://github.com/react-native-video/react-native-video/pull/2795/files) - -After that, -``` -yarn patch-package react-native-video -cd ios && pod install -yarn ios -``` - -### Running Android -If you get this Error -``` -Could not find com.yqritc:android-scalablevideoview:1.0.4. - Required by: - project :react-native-video - -``` -add this in `android/build.gradle` -``` -jcenter() { - content { - includeModule("com.yqritc", "android-scalablevideoview") - } -} -``` - -Run `yarn android` - - -### FOR REACT NATIVE CLI GENERATED APPS - -``` -npx install-expo-modules -expo install expo-file-system -expo install expo-linear-gradient -``` -``` -cd iOS && pod install -yarn iOS -``` - -Similarly, -if you get this [ViewPropTypes error](#viewproptypes-errorhttpsgithubcomfacebookreact-nativeissues33734issuecomment-1190506381) then use this [fix](#viewproptypes-error-fix) - -and [ImagePropTypes error](#imageproptypesresizemode-errorhttpsgithubcomreact-native-videoreact-native-videoissues2714) then use this [fix](https://github.com/react-native-video/react-native-video/pull/2795/files) - -## Notification Item View - -Import in your file -```typescript -import { Notification } from "@pushprotocol/reactnative"; -``` - -Inside JSX, - -After you get the Notification data from the API - -``` -const [notifData, setNotifData] = React.useState([]); - -// fetch data, parse and set it in state -import * as PushAPI from '@pushprotocol/restapi'; - - -const notifications = await PushAPI.user.getFeeds({ - user: 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681', - env: 'dev', - limit: parseInt(pageSize, 10) -}); -setNotifData(notifications); -``` - - -``` - <View style={styles.list}> - {notifData.map((oneNotification: any, idx: number) => { - const {cta, title, message, app, icon, image, blockchain, appbot } = oneNotification; - return ( - <Notification - key={idx} - notificationTitle={title} - notificationBody={message} - cta={cta} - app={app} - icon={icon} - image={image} - chainName={blockchain} - appbot={appbot} - youTubeAPIKey={config.YOUTUBE_API_KEY} // pass your YOUTUBE_API_KEY here - /> - ); - })} - </View> +```sh +npm install @push/react-native-sdk ``` - -where - -| Prop | Type | Remarks | -|----------|--------|--------------------------------------------| -| notificationTitle | string | Title of the notification (given during notification creation) | -| notificationBody | number | Message body of the notification (given during notification creation) | -| icon | string | Channel Icon (IPFS url) (given during channel setup) | -| app | string | Channel Name (given during channel setup) | -| 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", "ARBITRUM_TESTNET", "ARBITRUMONE_MAINNET", "THE_GRAPH" | -| youTubeAPIKey | string | Your generated Youtube API key | \ No newline at end of file diff --git a/packages/reactnative/android/build.gradle b/packages/reactnative/android/build.gradle new file mode 100644 index 000000000..d6bc45ca6 --- /dev/null +++ b/packages/reactnative/android/build.gradle @@ -0,0 +1,77 @@ +buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:7.2.1" + } +} + +def isNewArchitectureEnabled() { + return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" +} + +apply plugin: "com.android.library" + + +def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') } + +if (isNewArchitectureEnabled()) { + apply plugin: "com.facebook.react" +} + +def getExtOrDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["ReactNativeSdk_" + name] +} + +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["ReactNativeSdk_" + name]).toInteger() +} + +android { + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") + + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + } + buildTypes { + release { + minifyEnabled false + } + } + + lintOptions { + disable "GradleCompatible" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + +} + +repositories { + mavenCentral() + google() +} + + +dependencies { + // For < 0.71, this will be from the local maven repo + // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin + //noinspection GradleDynamicVersion + implementation "com.facebook.react:react-native:+" +} + +if (isNewArchitectureEnabled()) { + react { + jsRootDir = file("../src/") + libraryName = "ReactNativeSdkView" + codegenJavaPackageName = "com.push.reactnativesdk" + } +} diff --git a/packages/reactnative/android/gradle.properties b/packages/reactnative/android/gradle.properties new file mode 100644 index 000000000..f360eea5f --- /dev/null +++ b/packages/reactnative/android/gradle.properties @@ -0,0 +1,5 @@ +ReactNativeSdk_kotlinVersion=1.7.0 +ReactNativeSdk_minSdkVersion=21 +ReactNativeSdk_targetSdkVersion=31 +ReactNativeSdk_compileSdkVersion=31 +ReactNativeSdk_ndkversion=21.4.7075529 diff --git a/packages/reactnative/android/src/main/AndroidManifest.xml b/packages/reactnative/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..e3f2fadb7 --- /dev/null +++ b/packages/reactnative/android/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.push.reactnativesdk"> + +</manifest> diff --git a/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkPackage.java b/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkPackage.java new file mode 100644 index 000000000..300149461 --- /dev/null +++ b/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkPackage.java @@ -0,0 +1,22 @@ +package com.push.reactnativesdk; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class ReactNativeSdkPackage implements ReactPackage { + @Override + public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + + @Override + public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { + return Arrays.<ViewManager>asList(new ReactNativeSdkViewManager()); + } +} diff --git a/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkViewManager.java b/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkViewManager.java new file mode 100644 index 000000000..d8339ec09 --- /dev/null +++ b/packages/reactnative/android/src/main/java/com/push/reactnativesdk/ReactNativeSdkViewManager.java @@ -0,0 +1,31 @@ +package com.push.reactnativesdk; + +import android.graphics.Color; +import android.view.View; + +import androidx.annotation.NonNull; + +import com.facebook.react.uimanager.SimpleViewManager; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.annotations.ReactProp; + +public class ReactNativeSdkViewManager extends SimpleViewManager<View> { + public static final String REACT_CLASS = "ReactNativeSdkView"; + + @Override + @NonNull + public String getName() { + return REACT_CLASS; + } + + @Override + @NonNull + public View createViewInstance(ThemedReactContext reactContext) { + return new View(reactContext); + } + + @ReactProp(name = "color") + public void setColor(View view, String color) { + view.setBackgroundColor(Color.parseColor(color)); + } +} diff --git a/packages/reactnative/babel.config.js b/packages/reactnative/babel.config.js new file mode 100644 index 000000000..f842b77fc --- /dev/null +++ b/packages/reactnative/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ['module:metro-react-native-babel-preset'], +}; diff --git a/packages/reactnative/example/.bundle/config b/packages/reactnative/example/.bundle/config new file mode 100644 index 000000000..848943bb5 --- /dev/null +++ b/packages/reactnative/example/.bundle/config @@ -0,0 +1,2 @@ +BUNDLE_PATH: "vendor/bundle" +BUNDLE_FORCE_RUBY_PLATFORM: 1 diff --git a/packages/restapi/tests/.env.sample b/packages/reactnative/example/.env.sample similarity index 69% rename from packages/restapi/tests/.env.sample rename to packages/reactnative/example/.env.sample index 746fefeb5..f6d444362 100644 --- a/packages/restapi/tests/.env.sample +++ b/packages/reactnative/example/.env.sample @@ -2,9 +2,9 @@ WALLET_PRIVATE_KEY=your_wallet_private_key NFT_CONTRACT_ADDRESS_1=your_nft_contract_address NFT_CHAIN_ID_1=your_nft_chainid -NFT_TOKEN_ID_1=tour_nft_token_id +NFT_TOKEN_ID_1=your_nft_token_id NFT_HOLDER_WALLET_PRIVATE_KEY_1=wallet_private_key NFT_CONTRACT_ADDRESS_2=your_nft_contract_address NFT_CHAIN_ID_2=your_nft_chainid -NFT_TOKEN_ID_2=tour_nft_token_id -NFT_HOLDER_WALLET_PRIVATE_KEY_2=wallet_private_key \ No newline at end of file +NFT_TOKEN_ID_2=your_nft_token_id +NFT_HOLDER_WALLET_PRIVATE_KEY_2=wallet_private_key diff --git a/packages/reactnative/example/.node-version b/packages/reactnative/example/.node-version new file mode 100644 index 000000000..3c032078a --- /dev/null +++ b/packages/reactnative/example/.node-version @@ -0,0 +1 @@ +18 diff --git a/packages/reactnative/example/.watchmanconfig b/packages/reactnative/example/.watchmanconfig new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/packages/reactnative/example/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/reactnative/example/Gemfile b/packages/reactnative/example/Gemfile new file mode 100644 index 000000000..1142b1b20 --- /dev/null +++ b/packages/reactnative/example/Gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version +ruby '>= 2.6.10' + +gem 'cocoapods', '>= 1.11.3' diff --git a/packages/reactnative/example/android/app/build.gradle b/packages/reactnative/example/android/app/build.gradle new file mode 100644 index 000000000..146e8e65c --- /dev/null +++ b/packages/reactnative/example/android/app/build.gradle @@ -0,0 +1,170 @@ +apply plugin: "com.android.application" +apply plugin: "com.facebook.react" + +import com.android.build.OutputFile + +/** + * This is the configuration block to customize your React Native Android app. + * By default you don't need to apply any configuration, just uncomment the lines you need. + */ +react { + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '..' + // root = file("../") + // The folder where the react-native NPM package is. Default is ../node_modules/react-native + // reactNativeDir = file("../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen + // codegenDir = file("../node_modules/react-native-codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js + // cliFile = file("../node_modules/react-native/cli.js") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + // entryFile = file("../js/MyApplication.android.js") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] +} + +/** + * Set this to true to create four separate APKs instead of one, + * one for each native architecture. This is useful if you don't + * use App Bundles (https://developer.android.com/guide/app-bundle/) + * and want to have separate APKs to upload to the Play Store. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Set this to true to Run Proguard on Release builds to minify the Java bytecode. + */ +def enableProguardInReleaseBuilds = false + +/** + * The preferred build flavor of JavaScriptCore (JSC) + * + * For example, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ +def jscFlavor = 'org.webkit:android-jsc:+' + +/** + * Private function to get the list of Native Architectures you want to build. + * This reads the value from reactNativeArchitectures in your gradle.properties + * file and works together with the --active-arch-only flag of react-native run-android. + */ +def reactNativeArchitectures() { + def value = project.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] +} + +android { + ndkVersion rootProject.ext.ndkVersion + + compileSdkVersion rootProject.ext.compileSdkVersion + + namespace "com.reactnativesdkexample" + defaultConfig { + applicationId "com.reactnativesdkexample" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + } + + splits { + abi { + reset() + enable enableSeparateBuildPerCPUArchitecture + universalApk false // If true, also generate a universal APK + include (*reactNativeArchitectures()) + } + } + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { + // Caution! In production, you need to generate your own keystore file. + // see https://reactnative.dev/docs/signed-apk-android. + signingConfig signingConfigs.debug + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + } + } + + // applicationVariants are e.g. debug, release + applicationVariants.all { variant -> + variant.outputs.each { output -> + // For each separate APK per architecture, set a unique version code as described here: + // https://developer.android.com/studio/build/configure-apk-splits.html + // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc. + def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] + def abi = output.getFilter(OutputFile.ABI) + if (abi != null) { // null for the universal-debug, universal-release variants + output.versionCodeOverride = + defaultConfig.versionCode * 1000 + versionCodes.get(abi) + } + + } + } +} + +dependencies { + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-android") + + implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") + + debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") + debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { + exclude group:'com.squareup.okhttp3', module:'okhttp' + } + + debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") + if (hermesEnabled.toBoolean()) { + implementation("com.facebook.react:hermes-android") + } else { + implementation jscFlavor + } +} + +apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/packages/reactnative/example/android/app/debug.keystore b/packages/reactnative/example/android/app/debug.keystore new file mode 100644 index 000000000..364e105ed Binary files /dev/null and b/packages/reactnative/example/android/app/debug.keystore differ diff --git a/packages/reactnative/example/android/app/proguard-rules.pro b/packages/reactnative/example/android/app/proguard-rules.pro new file mode 100644 index 000000000..11b025724 --- /dev/null +++ b/packages/reactnative/example/android/app/proguard-rules.pro @@ -0,0 +1,10 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: diff --git a/packages/reactnative/example/android/app/src/debug/AndroidManifest.xml b/packages/reactnative/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 000000000..4b185bc15 --- /dev/null +++ b/packages/reactnative/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools"> + + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> + + <application + android:usesCleartextTraffic="true" + tools:targetApi="28" + tools:ignore="GoogleAppIndexingWarning"> + <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" /> + </application> +</manifest> diff --git a/packages/reactnative/example/android/app/src/debug/java/com/reactnativesdkexample/ReactNativeFlipper.java b/packages/reactnative/example/android/app/src/debug/java/com/reactnativesdkexample/ReactNativeFlipper.java new file mode 100644 index 000000000..28e270b48 --- /dev/null +++ b/packages/reactnative/example/android/app/src/debug/java/com/reactnativesdkexample/ReactNativeFlipper.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * <p>This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.reactnativesdkexample; + +import android.content.Context; +import com.facebook.flipper.android.AndroidFlipperClient; +import com.facebook.flipper.android.utils.FlipperUtils; +import com.facebook.flipper.core.FlipperClient; +import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; +import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; +import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; +import com.facebook.flipper.plugins.inspector.DescriptorMapping; +import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; +import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; +import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; +import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; +import com.facebook.react.ReactInstanceEventListener; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.modules.network.NetworkingModule; +import okhttp3.OkHttpClient; + +/** + * Class responsible of loading Flipper inside your React Native application. This is the debug + * flavor of it. Here you can add your own plugins and customize the Flipper setup. + */ +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + if (FlipperUtils.shouldEnableFlipper(context)) { + final FlipperClient client = AndroidFlipperClient.getInstance(context); + + client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); + client.addPlugin(new DatabasesFlipperPlugin(context)); + client.addPlugin(new SharedPreferencesFlipperPlugin(context)); + client.addPlugin(CrashReporterPlugin.getInstance()); + + NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); + NetworkingModule.setCustomClientBuilder( + new NetworkingModule.CustomClientBuilder() { + @Override + public void apply(OkHttpClient.Builder builder) { + builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); + } + }); + client.addPlugin(networkFlipperPlugin); + client.start(); + + // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized + // Hence we run if after all native modules have been initialized + ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); + if (reactContext == null) { + reactInstanceManager.addReactInstanceEventListener( + new ReactInstanceEventListener() { + @Override + public void onReactContextInitialized(ReactContext reactContext) { + reactInstanceManager.removeReactInstanceEventListener(this); + reactContext.runOnNativeModulesQueueThread( + new Runnable() { + @Override + public void run() { + client.addPlugin(new FrescoFlipperPlugin()); + } + }); + } + }); + } else { + client.addPlugin(new FrescoFlipperPlugin()); + } + } + } +} diff --git a/packages/reactnative/example/android/app/src/main/AndroidManifest.xml b/packages/reactnative/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..4122f36a5 --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android"> + + <uses-permission android:name="android.permission.INTERNET" /> + + <application + android:name=".MainApplication" + android:label="@string/app_name" + android:icon="@mipmap/ic_launcher" + android:roundIcon="@mipmap/ic_launcher_round" + android:allowBackup="false" + android:theme="@style/AppTheme"> + <activity + android:name=".MainActivity" + android:label="@string/app_name" + android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" + android:launchMode="singleTask" + android:windowSoftInputMode="adjustResize" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainActivity.java b/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainActivity.java new file mode 100644 index 000000000..93585fbcf --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainActivity.java @@ -0,0 +1,35 @@ +package com.reactnativesdkexample; + +import com.facebook.react.ReactActivity; +import com.facebook.react.ReactActivityDelegate; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactActivityDelegate; + +public class MainActivity extends ReactActivity { + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + @Override + protected String getMainComponentName() { + return "ReactNativeSdkExample"; + } + + /** + * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link + * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React + * (aka React 18) with two boolean flags. + */ + @Override + protected ReactActivityDelegate createReactActivityDelegate() { + return new DefaultReactActivityDelegate( + this, + getMainComponentName(), + // If you opted-in for the New Architecture, we enable the Fabric Renderer. + DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled + // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). + DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled + ); + } +} diff --git a/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainApplication.java b/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainApplication.java new file mode 100644 index 000000000..9f81d13c3 --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/java/com/reactnativesdkexample/MainApplication.java @@ -0,0 +1,62 @@ +package com.reactnativesdkexample; + +import android.app.Application; +import com.facebook.react.PackageList; +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactNativeHost; +import com.facebook.soloader.SoLoader; +import java.util.List; + +public class MainApplication extends Application implements ReactApplication { + + private final ReactNativeHost mReactNativeHost = + new DefaultReactNativeHost(this) { + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + @Override + protected List<ReactPackage> getPackages() { + @SuppressWarnings("UnnecessaryLocalVariable") + List<ReactPackage> packages = new PackageList(this).getPackages(); + // Packages that cannot be autolinked yet can be added manually here, for example: + // packages.add(new MyReactNativePackage()); + return packages; + } + + @Override + protected String getJSMainModuleName() { + return "index"; + } + + @Override + protected boolean isNewArchEnabled() { + return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + } + + @Override + protected Boolean isHermesEnabled() { + return BuildConfig.IS_HERMES_ENABLED; + } + }; + + @Override + public ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } + + @Override + public void onCreate() { + super.onCreate(); + SoLoader.init(this, /* native exopackage */ false); + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + DefaultNewArchitectureEntryPoint.load(); + } + ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); + } +} diff --git a/packages/reactnative/example/android/app/src/main/res/drawable/rn_edit_text_material.xml b/packages/reactnative/example/android/app/src/main/res/drawable/rn_edit_text_material.xml new file mode 100644 index 000000000..f35d99620 --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/res/drawable/rn_edit_text_material.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material" + android:insetRight="@dimen/abc_edit_text_inset_horizontal_material" + android:insetTop="@dimen/abc_edit_text_inset_top_material" + android:insetBottom="@dimen/abc_edit_text_inset_bottom_material"> + + <selector> + <!-- + This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I). + The item below with state_pressed="false" and state_focused="false" causes a NullPointerException. + NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)' + + <item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/> + + For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR. + --> + <item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/> + <item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/> + </selector> + +</inset> diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/reactnative/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..a2f590828 Binary files /dev/null and b/packages/reactnative/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/packages/reactnative/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..1b5239980 Binary files /dev/null and b/packages/reactnative/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/reactnative/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..ff10afd6e Binary files /dev/null and b/packages/reactnative/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/packages/reactnative/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..115a4c768 Binary files /dev/null and b/packages/reactnative/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/reactnative/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..dcd3cd808 Binary files /dev/null and b/packages/reactnative/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/packages/reactnative/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000..459ca609d Binary files /dev/null and b/packages/reactnative/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..8ca12fe02 Binary files /dev/null and b/packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..8e19b410a Binary files /dev/null and b/packages/reactnative/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/reactnative/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..b824ebdd4 Binary files /dev/null and b/packages/reactnative/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/reactnative/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/packages/reactnative/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..4c19a13c2 Binary files /dev/null and b/packages/reactnative/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/packages/reactnative/example/android/app/src/main/res/values/strings.xml b/packages/reactnative/example/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..9a4c824b4 --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ +<resources> + <string name="app_name">ReactNativeSdkExample</string> +</resources> diff --git a/packages/reactnative/example/android/app/src/main/res/values/styles.xml b/packages/reactnative/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..7ba83a2ad --- /dev/null +++ b/packages/reactnative/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,9 @@ +<resources> + + <!-- Base application theme. --> + <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar"> + <!-- Customize your theme here. --> + <item name="android:editTextBackground">@drawable/rn_edit_text_material</item> + </style> + +</resources> diff --git a/packages/reactnative/example/android/app/src/release/java/com/reactnativesdkexample/ReactNativeFlipper.java b/packages/reactnative/example/android/app/src/release/java/com/reactnativesdkexample/ReactNativeFlipper.java new file mode 100644 index 000000000..5491ad36b --- /dev/null +++ b/packages/reactnative/example/android/app/src/release/java/com/reactnativesdkexample/ReactNativeFlipper.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * <p>This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.reactnativesdkexample; + +import android.content.Context; +import com.facebook.react.ReactInstanceManager; + +/** + * Class responsible of loading Flipper inside your React Native application. This is the release + * flavor of it so it's empty as we don't want to load Flipper. + */ +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + // Do nothing as we don't want to initialize Flipper on Release. + } +} diff --git a/packages/reactnative/example/android/build.gradle b/packages/reactnative/example/android/build.gradle new file mode 100644 index 000000000..67d887b03 --- /dev/null +++ b/packages/reactnative/example/android/build.gradle @@ -0,0 +1,21 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext { + buildToolsVersion = "33.0.0" + minSdkVersion = 21 + compileSdkVersion = 33 + targetSdkVersion = 33 + + // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. + ndkVersion = "23.1.7779620" + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle:7.3.1") + classpath("com.facebook.react:react-native-gradle-plugin") + } +} diff --git a/packages/reactnative/example/android/gradle.properties b/packages/reactnative/example/android/gradle.properties new file mode 100644 index 000000000..e4af465e8 --- /dev/null +++ b/packages/reactnative/example/android/gradle.properties @@ -0,0 +1,44 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true + +# Version of flipper SDK to use with React Native +FLIPPER_VERSION=0.125.0 + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew <task> -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=false + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true diff --git a/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.jar b/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..41d9927a4 Binary files /dev/null and b/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..8fad3f5a9 --- /dev/null +++ b/packages/reactnative/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/packages/reactnative/example/android/gradlew b/packages/reactnative/example/android/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/packages/reactnative/example/android/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/packages/reactnative/example/android/gradlew.bat b/packages/reactnative/example/android/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/packages/reactnative/example/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/packages/reactnative/example/android/settings.gradle b/packages/reactnative/example/android/settings.gradle new file mode 100644 index 000000000..0dc839ff8 --- /dev/null +++ b/packages/reactnative/example/android/settings.gradle @@ -0,0 +1,4 @@ +rootProject.name = 'ReactNativeSdkExample' +apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) +include ':app' +includeBuild('../node_modules/react-native-gradle-plugin') diff --git a/packages/reactnative/example/app.json b/packages/reactnative/example/app.json new file mode 100644 index 000000000..45952059e --- /dev/null +++ b/packages/reactnative/example/app.json @@ -0,0 +1,4 @@ +{ + "name": "ReactNativeSdkExample", + "displayName": "ReactNativeSdkExample" +} \ No newline at end of file diff --git a/packages/reactnative/example/babel.config.js b/packages/reactnative/example/babel.config.js new file mode 100644 index 000000000..d66f68421 --- /dev/null +++ b/packages/reactnative/example/babel.config.js @@ -0,0 +1,25 @@ +const path = require('path'); +const pak = require('../package.json'); + +module.exports = { + presets: ['module:metro-react-native-babel-preset'], + plugins: [ + [ + 'module-resolver', + { + extensions: ['.tsx', '.ts', '.js', '.json'], + alias: { + [pak.name]: path.join(__dirname, '..', pak.source), + }, + }, + ], + [ + 'module:react-native-dotenv', + { + envName: 'APP_ENV', + moduleName: '@env', + path: '.env', + }, + ], + ], +}; diff --git a/packages/reactnative/example/index.js b/packages/reactnative/example/index.js new file mode 100644 index 000000000..117ddcae4 --- /dev/null +++ b/packages/reactnative/example/index.js @@ -0,0 +1,5 @@ +import { AppRegistry } from 'react-native'; +import App from './src/App'; +import { name as appName } from './app.json'; + +AppRegistry.registerComponent(appName, () => App); diff --git a/packages/reactnative/example/ios/File.swift b/packages/reactnative/example/ios/File.swift new file mode 100644 index 000000000..88c4f5252 --- /dev/null +++ b/packages/reactnative/example/ios/File.swift @@ -0,0 +1,6 @@ +// +// File.swift +// ReactNativeSdkExample +// + +import Foundation diff --git a/packages/reactnative/example/ios/Podfile b/packages/reactnative/example/ios/Podfile new file mode 100644 index 000000000..ef5d238fe --- /dev/null +++ b/packages/reactnative/example/ios/Podfile @@ -0,0 +1,60 @@ +require_relative '../node_modules/react-native/scripts/react_native_pods' +require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' + +platform :ios, min_ios_version_supported +prepare_react_native_project! + +# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. +# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded +# +# To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` +# ```js +# module.exports = { +# dependencies: { +# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), +# ``` +flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled + +linkage = ENV['USE_FRAMEWORKS'] +if linkage != nil + Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green + use_frameworks! :linkage => linkage.to_sym +end + +target 'ReactNativeSdkExample' do + config = use_native_modules! + + # Flags change depending on the env values. + flags = get_default_flags() + + use_react_native!( + :path => config[:reactNativePath], + # Hermes is now enabled by default. Disable by setting this flag to false. + # Upcoming versions of React Native may rely on get_default_flags(), but + # we make it explicit here to aid in the React Native upgrade process. + :hermes_enabled => flags[:hermes_enabled], + :fabric_enabled => flags[:fabric_enabled], + # Enables Flipper. + # + # Note that if you have use_frameworks! enabled, Flipper will not work and + # you should disable the next line. + :flipper_configuration => flipper_config, + # An absolute path to your application root. + :app_path => "#{Pod::Config.instance.installation_root}/.." + ) + + target 'ReactNativeSdkExampleTests' do + inherit! :complete + # Pods for testing + end + + post_install do |installer| + react_native_post_install( + installer, + # Set `mac_catalyst_enabled` to `true` in order to apply patches + # necessary for Mac Catalyst builds + :mac_catalyst_enabled => false + ) + __apply_Xcode_12_5_M1_post_install_workaround(installer) + end +end diff --git a/packages/reactnative/example/ios/Podfile.lock b/packages/reactnative/example/ios/Podfile.lock new file mode 100644 index 000000000..571da8c5e --- /dev/null +++ b/packages/reactnative/example/ios/Podfile.lock @@ -0,0 +1,641 @@ +PODS: + - boost (1.76.0) + - CocoaAsyncSocket (7.6.5) + - DoubleConversion (1.1.6) + - FBLazyVector (0.71.11) + - FBReactNativeSpec (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTRequired (= 0.71.11) + - RCTTypeSafety (= 0.71.11) + - React-Core (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - Flipper (0.125.0): + - Flipper-Folly (~> 2.6) + - Flipper-RSocket (~> 1.4) + - Flipper-Boost-iOSX (1.76.0.1.11) + - Flipper-DoubleConversion (3.2.0.1) + - Flipper-Fmt (7.1.7) + - Flipper-Folly (2.6.10): + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt (= 7.1.7) + - Flipper-Glog + - libevent (~> 2.1.12) + - OpenSSL-Universal (= 1.1.1100) + - Flipper-Glog (0.5.0.5) + - Flipper-PeerTalk (0.0.4) + - Flipper-RSocket (1.4.3): + - Flipper-Folly (~> 2.6) + - FlipperKit (0.125.0): + - FlipperKit/Core (= 0.125.0) + - FlipperKit/Core (0.125.0): + - Flipper (~> 0.125.0) + - FlipperKit/CppBridge + - FlipperKit/FBCxxFollyDynamicConvert + - FlipperKit/FBDefines + - FlipperKit/FKPortForwarding + - SocketRocket (~> 0.6.0) + - FlipperKit/CppBridge (0.125.0): + - Flipper (~> 0.125.0) + - FlipperKit/FBCxxFollyDynamicConvert (0.125.0): + - Flipper-Folly (~> 2.6) + - FlipperKit/FBDefines (0.125.0) + - FlipperKit/FKPortForwarding (0.125.0): + - CocoaAsyncSocket (~> 7.6) + - Flipper-PeerTalk (~> 0.0.4) + - FlipperKit/FlipperKitHighlightOverlay (0.125.0) + - FlipperKit/FlipperKitLayoutHelpers (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutTextSearchable + - FlipperKit/FlipperKitLayoutIOSDescriptors (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - YogaKit (~> 1.18) + - FlipperKit/FlipperKitLayoutPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - FlipperKit/FlipperKitLayoutIOSDescriptors + - FlipperKit/FlipperKitLayoutTextSearchable + - YogaKit (~> 1.18) + - FlipperKit/FlipperKitLayoutTextSearchable (0.125.0) + - FlipperKit/FlipperKitNetworkPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitReactPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitUserDefaultsPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/SKIOSNetworkPlugin (0.125.0): + - FlipperKit/Core + - FlipperKit/FlipperKitNetworkPlugin + - fmt (6.2.1) + - glog (0.3.5) + - hermes-engine (0.71.11): + - hermes-engine/Pre-built (= 0.71.11) + - hermes-engine/Pre-built (0.71.11) + - libevent (2.1.12) + - OpenSSL-Universal (1.1.1100) + - push-react-native-sdk (0.1.0): + - React-Core + - RCT-Folly (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Default (= 2021.07.22.00) + - RCT-Folly/Default (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Futures (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - libevent + - RCTRequired (0.71.11) + - RCTTypeSafety (0.71.11): + - FBLazyVector (= 0.71.11) + - RCTRequired (= 0.71.11) + - React-Core (= 0.71.11) + - React (0.71.11): + - React-Core (= 0.71.11) + - React-Core/DevSupport (= 0.71.11) + - React-Core/RCTWebSocket (= 0.71.11) + - React-RCTActionSheet (= 0.71.11) + - React-RCTAnimation (= 0.71.11) + - React-RCTBlob (= 0.71.11) + - React-RCTImage (= 0.71.11) + - React-RCTLinking (= 0.71.11) + - React-RCTNetwork (= 0.71.11) + - React-RCTSettings (= 0.71.11) + - React-RCTText (= 0.71.11) + - React-RCTVibration (= 0.71.11) + - React-callinvoker (0.71.11) + - React-Codegen (0.71.11): + - FBReactNativeSpec + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-jsi + - React-jsiexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-Core (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.11) + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/CoreModulesHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/Default (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/DevSupport (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.11) + - React-Core/RCTWebSocket (= 0.71.11) + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-jsinspector (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTActionSheetHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTAnimationHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTBlobHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTImageHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTLinkingHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTNetworkHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTSettingsHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTTextHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTVibrationHeaders (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-Core/RCTWebSocket (0.71.11): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.11) + - React-cxxreact (= 0.71.11) + - React-hermes + - React-jsi (= 0.71.11) + - React-jsiexecutor (= 0.71.11) + - React-perflogger (= 0.71.11) + - Yoga + - React-CoreModules (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.11) + - React-Codegen (= 0.71.11) + - React-Core/CoreModulesHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - React-RCTBlob + - React-RCTImage (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-cxxreact (0.71.11): + - boost (= 1.76.0) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.11) + - React-jsi (= 0.71.11) + - React-jsinspector (= 0.71.11) + - React-logger (= 0.71.11) + - React-perflogger (= 0.71.11) + - React-runtimeexecutor (= 0.71.11) + - React-hermes (0.71.11): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - RCT-Folly/Futures (= 2021.07.22.00) + - React-cxxreact (= 0.71.11) + - React-jsi + - React-jsiexecutor (= 0.71.11) + - React-jsinspector (= 0.71.11) + - React-perflogger (= 0.71.11) + - React-jsi (0.71.11): + - boost (= 1.76.0) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-jsiexecutor (0.71.11): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.71.11) + - React-jsi (= 0.71.11) + - React-perflogger (= 0.71.11) + - React-jsinspector (0.71.11) + - React-logger (0.71.11): + - glog + - react-native-fast-openpgp (2.6.0): + - React-Core + - react-native-webview (13.2.2): + - React-Core + - React-perflogger (0.71.11) + - React-RCTActionSheet (0.71.11): + - React-Core/RCTActionSheetHeaders (= 0.71.11) + - React-RCTAnimation (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.11) + - React-Codegen (= 0.71.11) + - React-Core/RCTAnimationHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTAppDelegate (0.71.11): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - ReactCommon/turbomodule/core + - React-RCTBlob (0.71.11): + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.71.11) + - React-Core/RCTBlobHeaders (= 0.71.11) + - React-Core/RCTWebSocket (= 0.71.11) + - React-jsi (= 0.71.11) + - React-RCTNetwork (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTImage (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.11) + - React-Codegen (= 0.71.11) + - React-Core/RCTImageHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - React-RCTNetwork (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTLinking (0.71.11): + - React-Codegen (= 0.71.11) + - React-Core/RCTLinkingHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTNetwork (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.11) + - React-Codegen (= 0.71.11) + - React-Core/RCTNetworkHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTSettings (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.11) + - React-Codegen (= 0.71.11) + - React-Core/RCTSettingsHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-RCTText (0.71.11): + - React-Core/RCTTextHeaders (= 0.71.11) + - React-RCTVibration (0.71.11): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.71.11) + - React-Core/RCTVibrationHeaders (= 0.71.11) + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/core (= 0.71.11) + - React-runtimeexecutor (0.71.11): + - React-jsi (= 0.71.11) + - ReactCommon/turbomodule/bridging (0.71.11): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.11) + - React-Core (= 0.71.11) + - React-cxxreact (= 0.71.11) + - React-jsi (= 0.71.11) + - React-logger (= 0.71.11) + - React-perflogger (= 0.71.11) + - ReactCommon/turbomodule/core (0.71.11): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.11) + - React-Core (= 0.71.11) + - React-cxxreact (= 0.71.11) + - React-jsi (= 0.71.11) + - React-logger (= 0.71.11) + - React-perflogger (= 0.71.11) + - SocketRocket (0.6.0) + - Yoga (1.14.0) + - YogaKit (1.18.1): + - Yoga (~> 1.14) + +DEPENDENCIES: + - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) + - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) + - Flipper (= 0.125.0) + - Flipper-Boost-iOSX (= 1.76.0.1.11) + - Flipper-DoubleConversion (= 3.2.0.1) + - Flipper-Fmt (= 7.1.7) + - Flipper-Folly (= 2.6.10) + - Flipper-Glog (= 0.5.0.5) + - Flipper-PeerTalk (= 0.0.4) + - Flipper-RSocket (= 1.4.3) + - FlipperKit (= 0.125.0) + - FlipperKit/Core (= 0.125.0) + - FlipperKit/CppBridge (= 0.125.0) + - FlipperKit/FBCxxFollyDynamicConvert (= 0.125.0) + - FlipperKit/FBDefines (= 0.125.0) + - FlipperKit/FKPortForwarding (= 0.125.0) + - FlipperKit/FlipperKitHighlightOverlay (= 0.125.0) + - FlipperKit/FlipperKitLayoutPlugin (= 0.125.0) + - FlipperKit/FlipperKitLayoutTextSearchable (= 0.125.0) + - FlipperKit/FlipperKitNetworkPlugin (= 0.125.0) + - FlipperKit/FlipperKitReactPlugin (= 0.125.0) + - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0) + - FlipperKit/SKIOSNetworkPlugin (= 0.125.0) + - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - libevent (~> 2.1.12) + - OpenSSL-Universal (= 1.1.1100) + - push-react-native-sdk (from `../..`) + - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) + - React-Codegen (from `build/generated/ios`) + - React-Core (from `../node_modules/react-native/`) + - React-Core/DevSupport (from `../node_modules/react-native/`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) + - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - react-native-fast-openpgp (from `../node_modules/react-native-fast-openpgp`) + - react-native-webview (from `../node_modules/react-native-webview`) + - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +SPEC REPOS: + trunk: + - CocoaAsyncSocket + - Flipper + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt + - Flipper-Folly + - Flipper-Glog + - Flipper-PeerTalk + - Flipper-RSocket + - FlipperKit + - fmt + - libevent + - OpenSSL-Universal + - SocketRocket + - YogaKit + +EXTERNAL SOURCES: + boost: + :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" + DoubleConversion: + :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + FBReactNativeSpec: + :path: "../node_modules/react-native/React/FBReactNativeSpec" + glog: + :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" + hermes-engine: + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + push-react-native-sdk: + :path: "../.." + RCT-Folly: + :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" + RCTRequired: + :path: "../node_modules/react-native/Libraries/RCTRequired" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" + React-Codegen: + :path: build/generated/ios + React-Core: + :path: "../node_modules/react-native/" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-hermes: + :path: "../node_modules/react-native/ReactCommon/hermes" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector" + React-logger: + :path: "../node_modules/react-native/ReactCommon/logger" + react-native-fast-openpgp: + :path: "../node_modules/react-native-fast-openpgp" + react-native-webview: + :path: "../node_modules/react-native-webview" + React-perflogger: + :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../node_modules/react-native/Libraries/AppDelegate" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + React-runtimeexecutor: + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + boost: 57d2868c099736d80fcd648bf211b4431e51a558 + CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 + DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 + FBLazyVector: c511d4cd0210f416cb5c289bd5ae6b36d909b048 + FBReactNativeSpec: a911fb22def57aef1d74215e8b6b8761d25c1c54 + Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0 + Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c + Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 + Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b + Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 + Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 + Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 + Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541 + FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 + fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 + glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b + hermes-engine: 34c863b446d0135b85a6536fa5fd89f48196f848 + libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 + OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c + push-react-native-sdk: d9d498989a0efa80523cfc7517ae24259d4a10f5 + RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCTRequired: f6187ec763637e6a57f5728dd9a3bdabc6d6b4e0 + RCTTypeSafety: a01aca2dd3b27fa422d5239252ad38e54e958750 + React: 741b4f5187e7a2137b69c88e65f940ba40600b4b + React-callinvoker: 72ba74b2d5d690c497631191ae6eeca0c043d9cf + React-Codegen: 8a7cda1633e4940de8a710f6bf5cae5dd673546e + React-Core: 72bb19702c465b6451a40501a2879532bec9acee + React-CoreModules: ffd19b082fc36b9b463fedf30955138b5426c053 + React-cxxreact: 8b3dd87e3b8ea96dd4ad5c7bac8f31f1cc3da97f + React-hermes: be95942c3f47fc032da1387360413f00dae0ea68 + React-jsi: 9978e2a64c2a4371b40e109f4ef30a33deaa9bcb + React-jsiexecutor: 18b5b33c5f2687a784a61bc8176611b73524ae77 + React-jsinspector: b6ed4cb3ffa27a041cd440300503dc512b761450 + React-logger: 186dd536128ae5924bc38ed70932c00aa740cd5b + react-native-fast-openpgp: 25df11a0fc3a801ef8fa6bd4335cb48c66dc5bbe + react-native-webview: b8ec89966713985111a14d6e4bf98d8b54bced0d + React-perflogger: e706562ab7eb8eb590aa83a224d26fa13963d7f2 + React-RCTActionSheet: 57d4bd98122f557479a3359ad5dad8e109e20c5a + React-RCTAnimation: ccf3ef00101ea74bda73a045d79a658b36728a60 + React-RCTAppDelegate: d0c28a35c65e9a0aef287ac0dafe1b71b1ac180c + React-RCTBlob: 1700b92ece4357af0a49719c9638185ad2902e95 + React-RCTImage: f2e4904566ccccaa4b704170fcc5ae144ca347bf + React-RCTLinking: 52a3740e3651e30aa11dff5a6debed7395dd8169 + React-RCTNetwork: ea0976f2b3ffc7877cd7784e351dc460adf87b12 + React-RCTSettings: ed5ac992b23e25c65c3cc31f11b5c940ae5e3e60 + React-RCTText: c9dfc6722621d56332b4f3a19ac38105e7504145 + React-RCTVibration: f09f08de63e4122deb32506e20ca4cae6e4e14c1 + React-runtimeexecutor: 4817d63dbc9d658f8dc0ec56bd9b83ce531129f0 + ReactCommon: 08723d2ed328c5cbcb0de168f231bc7bae7f8aa1 + SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 + Yoga: f7decafdc5e8c125e6fa0da38a687e35238420fa + YogaKit: f782866e155069a2cca2517aafea43200b01fd5a + +PODFILE CHECKSUM: c63b686a08336fbad705bcda149d6478884e7332 + +COCOAPODS: 1.12.1 diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample-Bridging-Header.h b/packages/reactnative/example/ios/ReactNativeSdkExample-Bridging-Header.h new file mode 100644 index 000000000..e11d920b1 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample-Bridging-Header.h @@ -0,0 +1,3 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/project.pbxproj b/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/project.pbxproj new file mode 100644 index 000000000..c3c77ab21 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/project.pbxproj @@ -0,0 +1,704 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 00E356F31AD99517003FC87E /* ReactNativeSdkExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ReactNativeSdkExampleTests.m */; }; + 0C80B921A6F3F58F76C31292 /* libPods-ReactNativeSdkExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-ReactNativeSdkExample.a */; }; + 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 7699B88040F8A987B510C191 /* libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a */; }; + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13B07F861A680F5B00A75B9A; + remoteInfo = ReactNativeSdkExample; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 00E356EE1AD99517003FC87E /* ReactNativeSdkExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactNativeSdkExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + 00E356F21AD99517003FC87E /* ReactNativeSdkExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactNativeSdkExampleTests.m; sourceTree = "<group>"; }; + 13B07F961A680F5B00A75B9A /* ReactNativeSdkExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReactNativeSdkExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ReactNativeSdkExample/AppDelegate.h; sourceTree = "<group>"; }; + 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = ReactNativeSdkExample/AppDelegate.mm; sourceTree = "<group>"; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ReactNativeSdkExample/Images.xcassets; sourceTree = "<group>"; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ReactNativeSdkExample/Info.plist; sourceTree = "<group>"; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactNativeSdkExample/main.m; sourceTree = "<group>"; }; + 19F6CBCC0A4E27FBF8BF4A61 /* libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B4392A12AC88292D35C810B /* Pods-ReactNativeSdkExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeSdkExample.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample.debug.xcconfig"; sourceTree = "<group>"; }; + 5709B34CF0A7D63546082F79 /* Pods-ReactNativeSdkExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeSdkExample.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample.release.xcconfig"; sourceTree = "<group>"; }; + 5B7EB9410499542E8C5724F5 /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.debug.xcconfig"; sourceTree = "<group>"; }; + 5DCACB8F33CDC322A6C60F78 /* libPods-ReactNativeSdkExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeSdkExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = ReactNativeSdkExample/LaunchScreen.storyboard; sourceTree = "<group>"; }; + 89C6BE57DB24E9ADA2F236DE /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.release.xcconfig"; sourceTree = "<group>"; }; + ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 00E356EB1AD99517003FC87E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7699B88040F8A987B510C191 /* libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0C80B921A6F3F58F76C31292 /* libPods-ReactNativeSdkExample.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 00E356EF1AD99517003FC87E /* ReactNativeSdkExampleTests */ = { + isa = PBXGroup; + children = ( + 00E356F21AD99517003FC87E /* ReactNativeSdkExampleTests.m */, + 00E356F01AD99517003FC87E /* Supporting Files */, + ); + path = ReactNativeSdkExampleTests; + sourceTree = "<group>"; + }; + 00E356F01AD99517003FC87E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 00E356F11AD99517003FC87E /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = "<group>"; + }; + 13B07FAE1A68108700A75B9A /* ReactNativeSdkExample */ = { + isa = PBXGroup; + children = ( + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.mm */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = ReactNativeSdkExample; + sourceTree = "<group>"; + }; + 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ED297162215061F000B7C4FE /* JavaScriptCore.framework */, + 5DCACB8F33CDC322A6C60F78 /* libPods-ReactNativeSdkExample.a */, + 19F6CBCC0A4E27FBF8BF4A61 /* libPods-ReactNativeSdkExample-ReactNativeSdkExampleTests.a */, + ); + name = Frameworks; + sourceTree = "<group>"; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = Libraries; + sourceTree = "<group>"; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* ReactNativeSdkExample */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 00E356EF1AD99517003FC87E /* ReactNativeSdkExampleTests */, + 83CBBA001A601CBA00E9B192 /* Products */, + 2D16E6871FA4F8E400B85C8A /* Frameworks */, + BBD78D7AC51CEA395F1C20DB /* Pods */, + ); + indentWidth = 2; + sourceTree = "<group>"; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* ReactNativeSdkExample.app */, + 00E356EE1AD99517003FC87E /* ReactNativeSdkExampleTests.xctest */, + ); + name = Products; + sourceTree = "<group>"; + }; + BBD78D7AC51CEA395F1C20DB /* Pods */ = { + isa = PBXGroup; + children = ( + 3B4392A12AC88292D35C810B /* Pods-ReactNativeSdkExample.debug.xcconfig */, + 5709B34CF0A7D63546082F79 /* Pods-ReactNativeSdkExample.release.xcconfig */, + 5B7EB9410499542E8C5724F5 /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.debug.xcconfig */, + 89C6BE57DB24E9ADA2F236DE /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.release.xcconfig */, + ); + path = Pods; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 00E356ED1AD99517003FC87E /* ReactNativeSdkExampleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactNativeSdkExampleTests" */; + buildPhases = ( + A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */, + 00E356EA1AD99517003FC87E /* Sources */, + 00E356EB1AD99517003FC87E /* Frameworks */, + 00E356EC1AD99517003FC87E /* Resources */, + C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */, + F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 00E356F51AD99517003FC87E /* PBXTargetDependency */, + ); + name = ReactNativeSdkExampleTests; + productName = ReactNativeSdkExampleTests; + productReference = 00E356EE1AD99517003FC87E /* ReactNativeSdkExampleTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 13B07F861A680F5B00A75B9A /* ReactNativeSdkExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeSdkExample" */; + buildPhases = ( + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */, + FD10A7F022414F080027D42C /* Start Packager */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */, + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ReactNativeSdkExample; + productName = ReactNativeSdkExample; + productReference = 13B07F961A680F5B00A75B9A /* ReactNativeSdkExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1210; + TargetAttributes = { + 00E356ED1AD99517003FC87E = { + CreatedOnToolsVersion = 6.2; + TestTargetID = 13B07F861A680F5B00A75B9A; + }; + 13B07F861A680F5B00A75B9A = { + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeSdkExample" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* ReactNativeSdkExample */, + 00E356ED1AD99517003FC87E /* ReactNativeSdkExampleTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 00E356EC1AD99517003FC87E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/.xcode.env.local", + "$(SRCROOT)/.xcode.env", + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; + }; + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ReactNativeSdkExample-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample/Pods-ReactNativeSdkExample-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests/Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + FD10A7F022414F080027D42C /* Start Packager */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Start Packager"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 00E356EA1AD99517003FC87E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 00E356F31AD99517003FC87E /* ReactNativeSdkExampleTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13B07F861A680F5B00A75B9A /* ReactNativeSdkExample */; + targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 00E356F61AD99517003FC87E /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = ReactNativeSdkExampleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeSdkExample.app/ReactNativeSdkExample"; + }; + name = Debug; + }; + 00E356F71AD99517003FC87E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-ReactNativeSdkExample-ReactNativeSdkExampleTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COPY_PHASE_STRIP = NO; + INFOPLIST_FILE = ReactNativeSdkExampleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReactNativeSdkExample.app/ReactNativeSdkExample"; + }; + name = Release; + }; + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-ReactNativeSdkExample.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = ReactNativeSdkExample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = ReactNativeSdkExample; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-ReactNativeSdkExample.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + INFOPLIST_FILE = ReactNativeSdkExample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = ReactNativeSdkExample; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactNativeSdkExampleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00E356F61AD99517003FC87E /* Debug */, + 00E356F71AD99517003FC87E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeSdkExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "ReactNativeSdkExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/xcshareddata/xcschemes/ReactNativeSdkExample.xcscheme b/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/xcshareddata/xcschemes/ReactNativeSdkExample.xcscheme new file mode 100644 index 000000000..c3bb832ce --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample.xcodeproj/xcshareddata/xcschemes/ReactNativeSdkExample.xcscheme @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "1210" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "13B07F861A680F5B00A75B9A" + BuildableName = "ReactNativeSdkExample.app" + BlueprintName = "ReactNativeSdkExample" + ReferencedContainer = "container:ReactNativeSdkExample.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "00E356ED1AD99517003FC87E" + BuildableName = "ReactNativeSdkExampleTests.xctest" + BlueprintName = "ReactNativeSdkExampleTests" + ReferencedContainer = "container:ReactNativeSdkExample.xcodeproj"> + </BuildableReference> + </TestableReference> + </Testables> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "13B07F861A680F5B00A75B9A" + BuildableName = "ReactNativeSdkExample.app" + BlueprintName = "ReactNativeSdkExample" + ReferencedContainer = "container:ReactNativeSdkExample.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "13B07F861A680F5B00A75B9A" + BuildableName = "ReactNativeSdkExample.app" + BlueprintName = "ReactNativeSdkExample" + ReferencedContainer = "container:ReactNativeSdkExample.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample.xcworkspace/contents.xcworkspacedata b/packages/reactnative/example/ios/ReactNativeSdkExample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..9be26e856 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "group:ReactNativeSdkExample.xcodeproj"> + </FileRef> + <FileRef + location = "group:Pods/Pods.xcodeproj"> + </FileRef> +</Workspace> diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.h b/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.h new file mode 100644 index 000000000..5d2808256 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.h @@ -0,0 +1,6 @@ +#import <RCTAppDelegate.h> +#import <UIKit/UIKit.h> + +@interface AppDelegate : RCTAppDelegate + +@end diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.mm b/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.mm new file mode 100644 index 000000000..8df3ed060 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/AppDelegate.mm @@ -0,0 +1,36 @@ +#import "AppDelegate.h" + +#import <React/RCTBundleURLProvider.h> + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.moduleName = @"ReactNativeSdkExample"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = @{}; + + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ +#if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; +#else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; +#endif +} + +/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. +/// +/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html +/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). +/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. +- (BOOL)concurrentRootEnabled +{ + return true; +} + +@end diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/AppIcon.appiconset/Contents.json b/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..81213230d --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/Contents.json b/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/Contents.json new file mode 100644 index 000000000..2d92bd53f --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/Info.plist b/packages/reactnative/example/ios/ReactNativeSdkExample/Info.plist new file mode 100644 index 000000000..e7a375d46 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/Info.plist @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleDisplayName</key> + <string>ReactNativeSdkExample</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>$(MARKETING_VERSION)</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>$(CURRENT_PROJECT_VERSION)</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>NSAppTransportSecurity</key> + <dict> + <key>NSExceptionDomains</key> + <dict> + <key>localhost</key> + <dict> + <key>NSExceptionAllowsInsecureHTTPLoads</key> + <true/> + </dict> + </dict> + </dict> + <key>NSLocationWhenInUseUsageDescription</key> + <string></string> + <key>UILaunchStoryboardName</key> + <string>LaunchScreen</string> + <key>UIRequiredDeviceCapabilities</key> + <array> + <string>armv7</string> + </array> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> + <key>UIViewControllerBasedStatusBarAppearance</key> + <false/> +</dict> +</plist> diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/LaunchScreen.storyboard b/packages/reactnative/example/ios/ReactNativeSdkExample/LaunchScreen.storyboard new file mode 100644 index 000000000..9e0f02713 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/LaunchScreen.storyboard @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> + <device id="retina4_7" orientation="portrait" appearance="light"/> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/> + <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="EHf-IW-A2E"> + <objects> + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ReactNativeSdkExample" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb"> + <rect key="frame" x="0.0" y="202" width="375" height="43"/> + <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="MN2-I3-ftu"> + <rect key="frame" x="0.0" y="626" width="375" height="21"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> + <constraints> + <constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" secondItem="MN2-I3-ftu" secondAttribute="bottom" constant="20" id="OZV-Vh-mqD"/> + <constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/> + <constraint firstItem="MN2-I3-ftu" firstAttribute="centerX" secondItem="Bcu-3y-fUS" secondAttribute="centerX" id="akx-eg-2ui"/> + <constraint firstItem="MN2-I3-ftu" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" id="i1E-0Y-4RG"/> + <constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/> + <constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="x7j-FC-K8j"/> + </constraints> + <viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="52.173913043478265" y="375"/> + </scene> + </scenes> +</document> diff --git a/packages/reactnative/example/ios/ReactNativeSdkExample/main.m b/packages/reactnative/example/ios/ReactNativeSdkExample/main.m new file mode 100644 index 000000000..d645c7246 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExample/main.m @@ -0,0 +1,10 @@ +#import <UIKit/UIKit.h> + +#import "AppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/packages/reactnative/example/ios/ReactNativeSdkExampleTests/Info.plist b/packages/reactnative/example/ios/ReactNativeSdkExampleTests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExampleTests/Info.plist @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>BNDL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1</string> +</dict> +</plist> diff --git a/packages/reactnative/example/ios/ReactNativeSdkExampleTests/ReactNativeSdkExampleTests.m b/packages/reactnative/example/ios/ReactNativeSdkExampleTests/ReactNativeSdkExampleTests.m new file mode 100644 index 000000000..b2523c458 --- /dev/null +++ b/packages/reactnative/example/ios/ReactNativeSdkExampleTests/ReactNativeSdkExampleTests.m @@ -0,0 +1,66 @@ +#import <UIKit/UIKit.h> +#import <XCTest/XCTest.h> + +#import <React/RCTLog.h> +#import <React/RCTRootView.h> + +#define TIMEOUT_SECONDS 600 +#define TEXT_TO_LOOK_FOR @"Welcome to React" + +@interface ReactNativeSdkExampleTests : XCTestCase + +@end + +@implementation ReactNativeSdkExampleTests + +- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test +{ + if (test(view)) { + return YES; + } + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; +} + +- (void)testRendersWelcomeScreen +{ + UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; + + __block NSString *redboxError = nil; +#ifdef DEBUG + RCTSetLogFunction( + ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { + if (level >= RCTLogLevelError) { + redboxError = message; + } + }); +#endif + + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + + foundElement = [self findSubviewInView:vc.view + matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; + } + +#ifdef DEBUG + RCTSetLogFunction(RCTDefaultLogFunction); +#endif + + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); +} + +@end diff --git a/packages/reactnative/example/metro.config.js b/packages/reactnative/example/metro.config.js new file mode 100644 index 000000000..b5c0064bb --- /dev/null +++ b/packages/reactnative/example/metro.config.js @@ -0,0 +1,40 @@ +const path = require('path'); +const escape = require('escape-string-regexp'); +const exclusionList = require('metro-config/src/defaults/exclusionList'); +const pak = require('../package.json'); + +const root = path.resolve(__dirname, '..'); + +const modules = Object.keys({ + ...pak.peerDependencies, +}); + +module.exports = { + projectRoot: __dirname, + watchFolders: [root], + + // We need to make sure that only one version is loaded for peerDependencies + // So we block them at the root, and alias them to the versions in example's node_modules + resolver: { + blacklistRE: exclusionList( + modules.map( + (m) => + new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) + ) + ), + + extraNodeModules: modules.reduce((acc, name) => { + acc[name] = path.join(__dirname, 'node_modules', name); + return acc; + }, {}), + }, + + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }), + }, +}; diff --git a/packages/reactnative/example/package.json b/packages/reactnative/example/package.json new file mode 100644 index 000000000..281c48666 --- /dev/null +++ b/packages/reactnative/example/package.json @@ -0,0 +1,33 @@ +{ + "name": "ReactNativeSdkExample", + "version": "0.0.1", + "private": true, + "scripts": { + "android": "react-native run-android", + "ios": "react-native run-ios", + "start": "react-native start", + "pods": "pod-install --quiet" + }, + "dependencies": { + "ethers": "^5.7.1", + "react": "18.2.0", + "react-native": "0.71.11", + "react-native-dotenv": "^3.4.9", + "react-native-fast-openpgp": "^2.6.0", + "react-native-webview": "^13.2.2", + "react-native-webview-crypto": "^0.0.25" + }, + "devDependencies": { + "@babel/core": "^7.20.0", + "@babel/preset-env": "^7.20.0", + "@babel/runtime": "^7.20.0", + "@tsconfig/react-native": "^3.0.2", + "@types/jest": "^29.5.2", + "@types/react": "^18.2.13", + "@types/react-native-dotenv": "^0.2.0", + "@types/react-test-renderer": "^18.0.0", + "babel-plugin-module-resolver": "^4.1.0", + "metro-react-native-babel-preset": "0.73.10", + "typescript": "^5.1.3" + } +} diff --git a/packages/reactnative/example/react-native.config.js b/packages/reactnative/example/react-native.config.js new file mode 100644 index 000000000..a5166956f --- /dev/null +++ b/packages/reactnative/example/react-native.config.js @@ -0,0 +1,10 @@ +const path = require('path'); +const pak = require('../package.json'); + +module.exports = { + dependencies: { + [pak.name]: { + root: path.join(__dirname, '..'), + }, + }, +}; diff --git a/packages/reactnative/example/shim.js b/packages/reactnative/example/shim.js new file mode 100644 index 000000000..812d6b45c --- /dev/null +++ b/packages/reactnative/example/shim.js @@ -0,0 +1,26 @@ +if (typeof __dirname === 'undefined') global.__dirname = '/' +if (typeof __filename === 'undefined') global.__filename = '' +if (typeof process === 'undefined') { + global.process = require('process') +} else { + const bProcess = require('process') + for (var p in bProcess) { + if (!(p in process)) { + process[p] = bProcess[p] + } + } +} + +process.browser = false +if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer + +// global.location = global.location || { port: 80 } +const isDev = typeof __DEV__ === 'boolean' && __DEV__ +process.env['NODE_ENV'] = isDev ? 'development' : 'production' +if (typeof localStorage !== 'undefined') { + localStorage.debug = isDev ? '*' : '' +} + +// If using the crypto shim, uncomment the following line to ensure +// crypto is loaded first, so it can populate global.crypto +// require('crypto') diff --git a/packages/reactnative/example/src/App.tsx b/packages/reactnative/example/src/App.tsx new file mode 100644 index 000000000..1ac463941 --- /dev/null +++ b/packages/reactnative/example/src/App.tsx @@ -0,0 +1,442 @@ +import React from 'react'; +import { ethers } from 'ethers'; + +import WebViewCrypto from 'react-native-webview-crypto'; +import { ScrollView, StyleSheet, Text } from 'react-native'; +import OpenPGP from 'react-native-fast-openpgp'; +import { + NFT_CHAIN_ID_1, + NFT_CHAIN_ID_2, + NFT_CONTRACT_ADDRESS_1, + NFT_CONTRACT_ADDRESS_2, + NFT_HOLDER_WALLET_PRIVATE_KEY_1, + NFT_HOLDER_WALLET_PRIVATE_KEY_2, + NFT_TOKEN_ID_1, + NFT_TOKEN_ID_2, +} from '@env'; +import { + PGPHelper, + genRandomAddress, + createUser, + ENV, + conversationHash, + latest, + createGroup, + updateGroup, + chats, + PushApi, + get, + profileUpdate, + decryptPGPKey, + profileUpgrade, + send, + Constants, + approve, +} from '@push/react-native-sdk'; + +function generatePrivateKey() { + // Define the set of characters for private key generation + var characters = '0123456789abcdef'; + + // Set the length of the private key (64 characters for 256 bits) + var keyLength = 64; + + // Generate the private key + var privateKey = ''; + for (var i = 0; i < keyLength; i++) { + var randomIndex = Math.floor(Math.random() * characters.length); + privateKey += characters.charAt(randomIndex); + } + + // Return the private key + return privateKey; +} + +function generateRandomString() { + var characters = '0123456789abcdef'; + var keyLength = 40; + var randomString = ''; + for (var i = 0; i < keyLength; i++) { + var randomIndex = Math.floor(Math.random() * characters.length); + randomString += characters.charAt(randomIndex); + } + return randomString; +} + +export default function App() { + const handlePgp = async () => { + let res = await PGPHelper.generateKeyPair(); + console.log(res); + }; + + const handleEthers = async () => { + let res = await genRandomAddress(); + console.log(res); + }; + + const handleUserCreate = async () => { + const pk = generatePrivateKey(); + + const signer = new ethers.Wallet(pk); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + + const options: PushApi.user.CreateUserProps = { + account: account, + signer: signer, + env: Constants.ENV.DEV, + }; + + console.log('create user', account); + + const res = await createUser(options); + console.log('success', res.did); + }; + + const handleUserMsgs = async () => { + const signer = new ethers.Wallet( + '07da77f7471e5cf046ea3793421cbce90fd42a4cfcf520046a490ca1a9b636e0' + ); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + console.log(signer); + + const res = await PushApi.chat.conversationHash({ + account: account, + conversationId: + 'b353220b812bdb707bd93529aac6fac893438e5db791d7c9e6aab6773aaff90b', + env: ENV.STAGING, + }); + + const res2 = await latest({ + threadhash: res.threadHash, + toDecrypt: true, + account: account, + env: ENV.STAGING, + }); + + const user = await PushApi.user.get({ + account: account, + env: ENV.STAGING, + }); + + const pgpDecryptedPvtKey = await PushApi.chat.decryptPGPKey({ + encryptedPGPPrivateKey: user.encryptedPrivateKey, + signer: signer, + }); + + const chatList = await chats({ + account: account, + pgpPrivateKey: pgpDecryptedPvtKey, + toDecrypt: true, + env: ENV.STAGING, + }); + console.log(user, 'user'); + console.log(pgpDecryptedPvtKey, 'key'); + console.log(chatList, 'Chatlist'); + }; + + const handleCreateGroup = async () => { + const pk = generatePrivateKey(); + const signer = new ethers.Wallet(pk); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + console.log(signer); + + const groupName = generateRandomString(); + + const res = await createGroup({ + groupName: groupName, + groupDescription: 'satyamstesing', + groupImage: 'https://github.com', + account: account, + signer: signer, + members: [ + '0x83d4c16b15F7BBA501Ca1057364a1F502d1c34D5', + '0x6Ff7DF70cAACAd6B35d2d30eca6bbb4E86fEE62f', + ], + admins: [], + isPublic: true, + env: ENV.DEV, + }); + console.log(res, 'res'); + + return { + chatId: res.chatId, + groupName, + signer, + }; + }; + + const handleUpdateGroup = async () => { + const { signer, chatId, groupName } = await handleCreateGroup(); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + + const res = await updateGroup({ + groupName, + groupDescription: 'satyamstesing', + groupImage: 'https://github.com', + chatId, + account: account, + signer: signer, + admins: ['0x83d4c16b15F7BBA501Ca1057364a1F502d1c34D5'], + members: [ + '0x6Ff7DF70cAACAd6B35d2d30eca6bbb4E86fEE62f', + '0x6d118b28ebd82635A30b142D11B9eEEa2c0bea26', + '0x83d4c16b15F7BBA501Ca1057364a1F502d1c34D5', + ], + env: ENV.DEV, + }); + console.log(res, 'ress'); + }; + + const handleGetUser = async () => { + const options: PushApi.AccountEnvOptionsType = { + account: '0xACEe0D180d0118FD4F3027Ab801cc862520570d1', + env: Constants.ENV.DEV, + }; + + const res = await get(options); + console.log('successfully got user', res); + }; + + const handleProfileUpdate = async () => { + console.log('updating profile...'); + const pk = generatePrivateKey(); + + const signer = new ethers.Wallet(pk); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + + console.log('creating user...'); + const user = await createUser({ + account: account, + signer: signer, + env: Constants.ENV.DEV, + }); + + console.log('decrypting pgp key...'); + const pgpPK = await decryptPGPKey({ + account: user.did, + encryptedPGPPrivateKey: user.encryptedPrivateKey, + env: Constants.ENV.DEV, + signer: signer, + }); + + console.log('updating profile...'); + await profileUpdate({ + account: account, + env: Constants.ENV.DEV, + pgpPrivateKey: pgpPK, + profile: { + name: 'Updated Name', + desc: 'Updated Desc', + }, + }); + console.log('successfully updated profile'); + }; + + const handleProfileUpgrade = async () => { + console.log('upgrading profile...'); + const pk = generatePrivateKey(); + const signer = new ethers.Wallet(pk); + const walletAddress = signer.address; + const account = `eip155:${walletAddress}`; + + const user = await createUser({ + account: account, + signer: signer, + env: Constants.ENV.DEV, + }); + + const pgpPK = await decryptPGPKey({ + account: user.did, + encryptedPGPPrivateKey: user.encryptedPrivateKey, + env: Constants.ENV.DEV, + signer: signer, + }); + + const pgpPubKey = await OpenPGP.convertPrivateKeyToPublicKey(pgpPK); + + const upgradedProfile = await profileUpgrade({ + signer: signer, + pgpPrivateKey: pgpPK, + pgpPublicKey: pgpPubKey, + pgpEncryptionVersion: Constants.ENCRYPTION_TYPE.NFTPGP_V1, + account: account, + env: Constants.ENV.DEV, + additionalMeta: { + NFTPGP_V1: { + password: '0x@1jdw89Amcedk', //new nft profile password + }, + }, + }); + + console.log('successfully upgraded profile'); + return upgradedProfile; + }; + + const handleSend = async () => { + const _nftSigner1 = new ethers.Wallet( + `0x${NFT_HOLDER_WALLET_PRIVATE_KEY_1}` + ); + const _nftWalletAddress1 = _nftSigner1.address; + console.log('sending...'); + console.log({ + NFT_CHAIN_ID: NFT_CHAIN_ID_1, + NFT_CONTRACT_ADDRESS: NFT_CONTRACT_ADDRESS_1, + NFT_TOKEN_ID: NFT_TOKEN_ID_1, + }); + const _nftAccount1 = `nft:eip155:${NFT_CHAIN_ID_1}:${NFT_CONTRACT_ADDRESS_1}:${NFT_TOKEN_ID_1}`; + const _nftSigner2 = new ethers.Wallet( + `0x${NFT_HOLDER_WALLET_PRIVATE_KEY_2}` + ); + const _nftWalletAddress2 = _nftSigner2.address; + const _nftAccount2 = `nft:eip155:${NFT_CHAIN_ID_2}:${NFT_CONTRACT_ADDRESS_2}:${NFT_TOKEN_ID_2}`; + + const pk1 = generatePrivateKey(); + const WALLET1 = new ethers.Wallet(pk1); + const _signer1 = new ethers.Wallet(WALLET1.privateKey); + const walletAddress1 = _signer1.address; + const account1 = `eip155:${walletAddress1}`; + + const pk2 = generatePrivateKey(); + const WALLET2 = new ethers.Wallet(pk2); + const _signer2 = new ethers.Wallet(WALLET2.privateKey); + const walletAddress2 = _signer2.address; + const account2 = `eip155:${walletAddress2}`; + + const MESSAGE = 'Hey There!!!'; + const MESSAGE2 = 'Hey There Upgraded User!!!'; + const MESSAGE3 = 'Hey There from Upgraded User!!!'; + + const _env = Constants.ENV.DEV; + + await send({ + messageContent: MESSAGE, + receiverAddress: _nftAccount1, + account: account1, + signer: _signer1, + env: _env, + }); + + await send({ + messageContent: MESSAGE, + receiverAddress: account1, + account: _nftAccount1, + signer: _nftSigner1, + env: _env, + }); + + await send({ + messageContent: MESSAGE, + receiverAddress: _nftAccount2, + account: _nftAccount1, + signer: _nftSigner1, + env: _env, + }); + console.log('sent message!'); + }; + + const handleApproveRequest = async () => { + console.log('sending request...'); + + const pk1 = generatePrivateKey(); + const pk2 = generatePrivateKey(); + + const signer1 = new ethers.Wallet(pk1); + const signer2 = new ethers.Wallet(pk2); + + const account1 = `eip155:${signer1.address}`; + const account2 = `eip155:${signer2.address}`; + + const MESSAGE = 'Hey There!!!'; + + await createUser({ + account: account1, + signer: signer1, + env: Constants.ENV.DEV, + }); + + await createUser({ + account: account2, + signer: signer2, + env: Constants.ENV.DEV, + }); + + await send({ + messageContent: MESSAGE, + receiverAddress: signer2.address, + account: account1, + signer: signer1, + env: Constants.ENV.DEV, + }); + + console.log('approving request...'); + await approve({ + senderAddress: signer1.address, + status: 'Approved', + account: account2, + signer: signer2, + env: Constants.ENV.DEV, + }); + + console.log('successfully approved request!'); + }; + + return ( + <ScrollView style={styles.container} overScrollMode="never"> + <WebViewCrypto /> + <Text style={styles.button} onPress={handleUserCreate}> + New User + </Text> + <Text style={styles.button} onPress={handlePgp}> + Generate PGP Pair + </Text> + <Text style={styles.button} onPress={handleEthers}> + Log Address + </Text> + <Text style={styles.button} onPress={handleCreateGroup}> + Create Group + </Text> + <Text style={styles.button} onPress={handleUpdateGroup}> + update group + </Text> + <Text style={styles.button} onPress={handleUserMsgs}> + ConversationHash + </Text> + <Text style={styles.button} onPress={handleGetUser}> + Get user + </Text> + <Text style={styles.button} onPress={handleProfileUpdate}> + Update Profile + </Text> + <Text style={styles.button} onPress={handleProfileUpgrade}> + Upgrade Profile + </Text> + <Text style={styles.button} onPress={handleSend}> + Send Message + </Text> + <Text style={styles.button} onPress={handleApproveRequest}> + Approve Request + </Text> + </ScrollView> + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + box: { + width: 60, + height: 60, + marginVertical: 20, + }, + button: { + padding: 10, + fontSize: 32, + margin: 10, + }, +}); diff --git a/packages/reactnative/example/tsconfig.json b/packages/reactnative/example/tsconfig.json new file mode 100644 index 000000000..b71c72cc6 --- /dev/null +++ b/packages/reactnative/example/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@tsconfig/react-native/tsconfig.json", +} diff --git a/packages/reactnative/example/types/env.d.ts b/packages/reactnative/example/types/env.d.ts new file mode 100644 index 000000000..d01acb281 --- /dev/null +++ b/packages/reactnative/example/types/env.d.ts @@ -0,0 +1,12 @@ +declare module '@env' { + export const ENV: string; + export const WALLET_PRIVATE_KEY: string; + export const NFT_CONTRACT_ADDRESS_1: string; + export const NFT_CHAIN_ID_1: string; + export const NFT_TOKEN_ID_1: string; + export const NFT_HOLDER_WALLET_PRIVATE_KEY_1: string; + export const NFT_CONTRACT_ADDRESS_2: string; + export const NFT_CHAIN_ID_2: string; + export const NFT_TOKEN_ID_2: string; + export const NFT_HOLDER_WALLET_PRIVATE_KEY_2: string; +} diff --git a/packages/reactnative/ios/ReactNativeSdk.xcodeproj/project.pbxproj b/packages/reactnative/ios/ReactNativeSdk.xcodeproj/project.pbxproj new file mode 100644 index 000000000..14e8dfeed --- /dev/null +++ b/packages/reactnative/ios/ReactNativeSdk.xcodeproj/project.pbxproj @@ -0,0 +1,274 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E555C0D2413F4C50049A1A2 /* ReactNativeSdk.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* ReactNativeSdk.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 58B511D91A9E6C8500147676 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 134814201AA4EA6300B7C361 /* libReactNativeSdk.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libReactNativeSdk.a; sourceTree = BUILT_PRODUCTS_DIR; }; + B3E7B5881CC2AC0600A0062D /* ReactNativeSdk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReactNativeSdk.h; sourceTree = "<group>"; }; + B3E7B5891CC2AC0600A0062D /* ReactNativeSdk.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReactNativeSdk.m; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 58B511D81A9E6C8500147676 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 134814211AA4EA7D00B7C361 /* Products */ = { + isa = PBXGroup; + children = ( + 134814201AA4EA6300B7C361 /* libReactNativeSdk.a */, + ); + name = Products; + sourceTree = "<group>"; + }; + 58B511D21A9E6C8500147676 = { + isa = PBXGroup; + children = ( + B3E7B5881CC2AC0600A0062D /* ReactNativeSdk.h */, + B3E7B5891CC2AC0600A0062D /* ReactNativeSdk.m */, + 134814211AA4EA7D00B7C361 /* Products */, + ); + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 58B511DA1A9E6C8500147676 /* ReactNativeSdk */ = { + isa = PBXNativeTarget; + buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "ReactNativeSdk" */; + buildPhases = ( + 58B511D71A9E6C8500147676 /* Sources */, + 58B511D81A9E6C8500147676 /* Frameworks */, + 58B511D91A9E6C8500147676 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ReactNativeSdk; + productName = RCTDataManager; + productReference = 134814201AA4EA6300B7C361 /* libReactNativeSdk.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 58B511D31A9E6C8500147676 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0920; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 58B511DA1A9E6C8500147676 = { + CreatedOnToolsVersion = 6.1.1; + }; + }; + }; + buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "ReactNativeSdk" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + English, + en, + ); + mainGroup = 58B511D21A9E6C8500147676; + productRefGroup = 58B511D21A9E6C8500147676; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 58B511DA1A9E6C8500147676 /* ReactNativeSdk */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 58B511D71A9E6C8500147676 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B3E7B58A1CC2AC0600A0062D /* ReactNativeSdk.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 58B511ED1A9E6C8500147676 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + "EXCLUDED_ARCHS[sdk=*]" = arm64; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 58B511EE1A9E6C8500147676 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + "EXCLUDED_ARCHS[sdk=*]" = arm64; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 58B511F01A9E6C8500147676 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../../React/**", + "$(SRCROOT)/../../react-native/React/**", + ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ReactNativeSdk; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 58B511F11A9E6C8500147676 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../../React/**", + "$(SRCROOT)/../../react-native/React/**", + ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ReactNativeSdk; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "ReactNativeSdk" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 58B511ED1A9E6C8500147676 /* Debug */, + 58B511EE1A9E6C8500147676 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "ReactNativeSdk" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 58B511F01A9E6C8500147676 /* Debug */, + 58B511F11A9E6C8500147676 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 58B511D31A9E6C8500147676 /* Project object */; +} diff --git a/packages/reactnative/ios/ReactNativeSdkViewManager.m b/packages/reactnative/ios/ReactNativeSdkViewManager.m new file mode 100644 index 000000000..661383f12 --- /dev/null +++ b/packages/reactnative/ios/ReactNativeSdkViewManager.m @@ -0,0 +1,34 @@ +#import <React/RCTViewManager.h> + +@interface ReactNativeSdkViewManager : RCTViewManager +@end + +@implementation ReactNativeSdkViewManager + +RCT_EXPORT_MODULE(ReactNativeSdkView) + +- (UIView *)view +{ + return [[UIView alloc] init]; +} + +RCT_CUSTOM_VIEW_PROPERTY(color, NSString, UIView) +{ + [view setBackgroundColor:[self hexStringToColor:json]]; +} + +- hexStringToColor:(NSString *)stringToConvert +{ + NSString *noHashString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""]; + NSScanner *stringScanner = [NSScanner scannerWithString:noHashString]; + + unsigned hex; + if (![stringScanner scanHexInt:&hex]) return nil; + int r = (hex >> 16) & 0xFF; + int g = (hex >> 8) & 0xFF; + int b = (hex) & 0xFF; + + return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f]; +} + +@end diff --git a/packages/reactnative/package.json b/packages/reactnative/package.json index 8978987cc..e5f689dfc 100644 --- a/packages/reactnative/package.json +++ b/packages/reactnative/package.json @@ -1,25 +1,219 @@ { - "name": "@pushprotocol/reactnative", - "version": "0.2.0", + "name": "@push/react-native-sdk", + "version": "0.1.0", + "description": "test", + "main": "lib/commonjs/index", + "module": "lib/module/index", + "types": "lib/typescript/index.d.ts", + "react-native": { + "lib/commonjs/index": "src/index", + "crypto": "react-native-crypto", + "net": "react-native-tcp", + "http": "@tradle/react-native-http", + "https": "https-browserify", + "os": "react-native-os", + "fs": "react-native-level-fs", + "_stream_transform": "readable-stream/transform", + "_stream_readable": "readable-stream/readable", + "_stream_writable": "readable-stream/writable", + "_stream_duplex": "readable-stream/duplex", + "_stream_passthrough": "readable-stream/passthrough", + "stream": "stream-browserify" + }, + "source": "src/index", + "files": [ + "src", + "lib", + "android", + "ios", + "cpp", + "*.podspec", + "!lib/typescript/example", + "!ios/build", + "!android/build", + "!android/gradle", + "!android/gradlew", + "!android/gradlew.bat", + "!android/local.properties", + "!**/__tests__", + "!**/__fixtures__", + "!**/__mocks__", + "!**/.*" + ], + "scripts": { + "test": "jest", + "typecheck": "tsc --noEmit", + "lint": "eslint \"**/*.{js,ts,tsx}\"", + "prepack": "bob build", + "release": "release-it", + "example": "yarn --cwd example", + "bootstrap": "yarn example && yarn install && yarn example pods", + "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build", + "postinstall": "node_modules/.bin/rn-nodeify --install crypto,assert,url,stream,events,http,https,os,url,net,fs --hack && patch-package" + }, + "keywords": [ + "react-native", + "ios", + "android" + ], + "repository": "https://github.com/ethereum-push-notification-service/push-sdk", + "author": "Push Protocol <support@push.org> (https://www.push.org)", + "license": "MIT", + "bugs": { + "url": "https://github.com/ethereum-push-notification-service/push-sdk/issues" + }, + "homepage": "https://github.com/ethereum-push-notification-service/push-sdk#readme", "publishConfig": { "registry": "https://registry.npmjs.org/" }, + "dependencies": { + "@pushprotocol/restapi": "../../dist/packages/restapi", + "@tradle/react-native-http": "^2.0.1", + "assert": "^1.5.0", + "crypto": "^1.0.1", + "crypto-js": "3.1.9-1", + "ethers": "^5.7.1", + "events": "^3.3.0", + "https-browserify": "^0.0.1", + "process": "^0.11.10", + "react-native-crypto": "^2.2.0", + "react-native-fast-openpgp": "^2.6.0", + "react-native-get-random-values": "^1.9.0", + "react-native-level-fs": "^3.0.1", + "react-native-os": "^1.2.6", + "react-native-randombytes": "^3.6.1", + "react-native-tcp": "^3.3.2", + "react-native-webview": "^11.26.1", + "react-native-webview-crypto": "^0.0.25", + "readable-stream": "^1.0.33", + "stream": "^0.0.2", + "stream-browserify": "^1.0.0", + "text-encoding": "0.7.0", + "url": "^0.10.3" + }, + "devDependencies": { + "@commitlint/config-conventional": "^17.0.2", + "@evilmartians/lefthook": "^1.2.2", + "@react-native-community/eslint-config": "^3.0.2", + "@release-it/conventional-changelog": "^5.0.0", + "@types/jest": "^28.1.2", + "@types/react": "~17.0.21", + "@types/react-native": "0.70.0", + "commitlint": "^17.0.2", + "del-cli": "^5.0.0", + "eslint": "^8.4.1", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.0.0", + "jest": "^28.1.1", + "patch-package": "^7.0.0", + "pod-install": "^0.1.0", + "postinstall-postinstall": "^2.1.0", + "prettier": "^2.0.5", + "react": "18.2.0", + "react-native": "0.71.11", + "react-native-builder-bob": "^0.20.4", + "release-it": "^15.0.0", + "rn-nodeify": "^10.3.0", + "typescript": "^4.5.2" + }, + "resolutions": { + "@types/react": "17.0.21" + }, "peerDependencies": { - "@react-native-masked-view/masked-view": "^0.2.7", - "expo": "^45.0.0", - "expo-file-system": "^14.0.0", - "expo-linear-gradient": "^11.3.0", - "react": "^17.0.2 || ^18.0.0", - "react-native": "^0.68.2", - "react-native-svg": "^12.3.0", - "react-native-video": "^5.2.0", - "react-native-youtube": "^2.0.2" + "react": "*", + "react-native": "*", + "react-native-fast-openpgp": "^2.6.0" }, - "dependencies": { - "moment": "^2.29.4", - "react-native-device-detection": "^0.2.1", - "react-native-modal": "^13.0.1", - "react-native-parsed-text": "^0.0.22", - "react-native-progress-circle": "^2.1.0" + "engines": { + "node": ">= 16.0.0" + }, + "packageManager": "^yarn@1.22.15", + "jest": { + "preset": "react-native", + "modulePathIgnorePatterns": [ + "<rootDir>/example/node_modules", + "<rootDir>/lib/" + ] + }, + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "release-it": { + "git": { + "commitMessage": "chore: release ${version}", + "tagName": "v${version}" + }, + "npm": { + "publish": true + }, + "github": { + "release": true + }, + "plugins": { + "@release-it/conventional-changelog": { + "preset": "angular" + } + } + }, + "eslintConfig": { + "root": true, + "extends": [ + "@react-native-community", + "prettier" + ], + "rules": { + "prettier/prettier": [ + "error", + { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + } + ] + } + }, + "eslintIgnore": [ + "node_modules/", + "lib/" + ], + "prettier": { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + }, + "react-native-builder-bob": { + "source": "src", + "output": "lib", + "targets": [ + "commonjs", + "module", + [ + "typescript", + { + "project": "tsconfig.build.json" + } + ] + ] + }, + "browser": { + "lib/commonjs/index": "src/index", + "crypto": "react-native-crypto", + "net": "react-native-tcp", + "http": "@tradle/react-native-http", + "https": "https-browserify", + "os": "react-native-os", + "fs": "react-native-level-fs", + "_stream_transform": "readable-stream/transform", + "_stream_readable": "readable-stream/readable", + "_stream_writable": "readable-stream/writable", + "_stream_duplex": "readable-stream/duplex", + "_stream_passthrough": "readable-stream/passthrough", + "stream": "stream-browserify" } } diff --git a/packages/reactnative/patches/micro-ftch+0.3.1.patch b/packages/reactnative/patches/micro-ftch+0.3.1.patch new file mode 100644 index 000000000..0e91bb169 --- /dev/null +++ b/packages/reactnative/patches/micro-ftch+0.3.1.patch @@ -0,0 +1,17 @@ +diff --git a/node_modules/micro-ftch/index.js b/node_modules/micro-ftch/index.js +index 7f00c3d..da4a27f 100644 +--- a/node_modules/micro-ftch/index.js ++++ b/node_modules/micro-ftch/index.js +@@ -51,9 +51,9 @@ function detectType(b, type) { + let agents = {}; + function fetchNode(url, _options) { + let options = { ...DEFAULT_OPT, ..._options }; +- const http = require('http'); +- const https = require('https'); +- const zlib = require('zlib'); ++ const http = {}; ++ const https = {}; ++ const zlib = {}; + const { promisify } = require('util'); + const { resolve: urlResolve } = require('url'); + const isSecure = !!/^https/.test(url); diff --git a/packages/reactnative/patches/react-native-randombytes+3.6.1.patch b/packages/reactnative/patches/react-native-randombytes+3.6.1.patch new file mode 100644 index 000000000..fc9c6a000 --- /dev/null +++ b/packages/reactnative/patches/react-native-randombytes+3.6.1.patch @@ -0,0 +1,23 @@ +diff --git a/node_modules/react-native-randombytes/index.js b/node_modules/react-native-randombytes/index.js +index 7478cb3..bd2ecbd 100644 +--- a/node_modules/react-native-randombytes/index.js ++++ b/node_modules/react-native-randombytes/index.js +@@ -12,11 +12,13 @@ function toBuffer (nativeStr) { + } + + function init () { +- if (RNRandomBytes.seed) { +- let seedBuffer = toBuffer(RNRandomBytes.seed) +- addEntropy(seedBuffer) +- } else { +- seedSJCL() ++ if(RNRandomBytes){ ++ if (RNRandomBytes.seed) { ++ let seedBuffer = toBuffer(RNRandomBytes.seed) ++ addEntropy(seedBuffer) ++ } else { ++ seedSJCL() ++ } + } + } + diff --git a/packages/reactnative/push-react-native-sdk.podspec b/packages/reactnative/push-react-native-sdk.podspec new file mode 100644 index 000000000..adccca4bc --- /dev/null +++ b/packages/reactnative/push-react-native-sdk.podspec @@ -0,0 +1,36 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) +folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' + +Pod::Spec.new do |s| + s.name = "push-react-native-sdk" + s.version = package["version"] + s.summary = package["description"] + s.homepage = package["homepage"] + s.license = package["license"] + s.authors = package["author"] + + s.platforms = { :ios => "11.0" } + s.source = { :git => "https://github.com/ethereum-push-notification-service/push-sdk.git", :tag => "#{s.version}" } + + s.source_files = "ios/**/*.{h,m,mm}" + + s.dependency "React-Core" + + # Don't install the dependencies when we run `pod install` in the old architecture. + if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then + s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" + s.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", + "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" + } + s.dependency "React-RCTFabric" + s.dependency "React-Codegen" + s.dependency "RCT-Folly" + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "ReactCommon/turbomodule/core" + end +end diff --git a/packages/reactnative/rollup.config.cjs b/packages/reactnative/rollup.config.cjs deleted file mode 100644 index 1bfee03c8..000000000 --- a/packages/reactnative/rollup.config.cjs +++ /dev/null @@ -1,26 +0,0 @@ -const nrwlConfig = require('@nrwl/react/plugins/bundle-rollup'); -const replace = require('@rollup/plugin-replace'); - -module.exports = (config) => { - const nxConfig = nrwlConfig(config); - - return { - ...nxConfig, - plugins: [ - ...nxConfig.plugins, - - /** - * IMAGE path hack for packaged library to be able to read images on - * the BUNDLE path instead of the SOURCE path - */ - replace({ - values: { - '../../assets/frownface.png': './lib/assets/frownface.png', - '../../assets/epnsbot.png': './lib/assets/epnsbot.png' - }, - delimiters: ['', ''], - }) - - ] - }; -} \ No newline at end of file diff --git a/packages/reactnative/scripts/bootstrap.js b/packages/reactnative/scripts/bootstrap.js new file mode 100644 index 000000000..172918947 --- /dev/null +++ b/packages/reactnative/scripts/bootstrap.js @@ -0,0 +1,29 @@ +const os = require('os'); +const path = require('path'); +const child_process = require('child_process'); + +const root = path.resolve(__dirname, '..'); +const args = process.argv.slice(2); +const options = { + cwd: process.cwd(), + env: process.env, + stdio: 'inherit', + encoding: 'utf-8', +}; + +if (os.type() === 'Windows_NT') { + options.shell = true; +} + +let result; + +if (process.cwd() !== root || args.length) { + // We're not in the root of the project, or additional arguments were passed + // In this case, forward the command to `yarn` + result = child_process.spawnSync('yarn', args, options); +} else { + // If `yarn` is run without arguments, perform bootstrap + result = child_process.spawnSync('yarn', ['bootstrap'], options); +} + +process.exitCode = result.status; diff --git a/packages/reactnative/shim.js b/packages/reactnative/shim.js new file mode 100644 index 000000000..812d6b45c --- /dev/null +++ b/packages/reactnative/shim.js @@ -0,0 +1,26 @@ +if (typeof __dirname === 'undefined') global.__dirname = '/' +if (typeof __filename === 'undefined') global.__filename = '' +if (typeof process === 'undefined') { + global.process = require('process') +} else { + const bProcess = require('process') + for (var p in bProcess) { + if (!(p in process)) { + process[p] = bProcess[p] + } + } +} + +process.browser = false +if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer + +// global.location = global.location || { port: 80 } +const isDev = typeof __DEV__ === 'boolean' && __DEV__ +process.env['NODE_ENV'] = isDev ? 'development' : 'production' +if (typeof localStorage !== 'undefined') { + localStorage.debug = isDev ? '*' : '' +} + +// If using the crypto shim, uncomment the following line to ensure +// crypto is loaded first, so it can populate global.crypto +// require('crypto') diff --git a/packages/reactnative/src/__tests__/index.test.tsx b/packages/reactnative/src/__tests__/index.test.tsx new file mode 100644 index 000000000..92643deb6 --- /dev/null +++ b/packages/reactnative/src/__tests__/index.test.tsx @@ -0,0 +1,4 @@ +import { PushApi } from '../index'; +it('write a test', async () => { + console.log(PushApi); +}); diff --git a/packages/reactnative/src/index.ts b/packages/reactnative/src/index.ts deleted file mode 100644 index 47945b57c..000000000 --- a/packages/reactnative/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './lib'; \ No newline at end of file diff --git a/packages/reactnative/src/index.tsx b/packages/reactnative/src/index.tsx new file mode 100644 index 000000000..60cf5f630 --- /dev/null +++ b/packages/reactnative/src/index.tsx @@ -0,0 +1,140 @@ +import '../shim.js'; +import 'text-encoding'; +import 'react-native-crypto'; +import 'react-native-get-random-values'; + +import OpenPGP from 'react-native-fast-openpgp'; +import { ethers } from 'ethers'; + +import * as PushApi from '@pushprotocol/restapi'; +import { IPGPHelper } from '@pushprotocol/restapi/src/lib/chat/helpers/pgp.js'; +import { ENV } from '@pushprotocol/restapi/src/lib/constants.js'; +import { LatestMessagesOptionsType } from '@pushprotocol/restapi/src/lib/chat/latestMessage.js'; +import { HistoricalMessagesOptionsType } from '@pushprotocol/restapi/src/lib/chat/historicalMessages.js'; +import { ChatCreateGroupType } from '@pushprotocol/restapi/src/lib/chat/createGroup.js'; +import { ChatUpdateGroupType } from '@pushprotocol/restapi/src/lib/chat/updateGroup.js'; +import { ChatsOptionsType } from '@pushprotocol/restapi/src/lib/chat/chats.js'; +import Constants from '@pushprotocol/restapi/src/lib/constants.js'; +import { decryptPGPKey } from '@pushprotocol/restapi/src/lib/helpers/crypto.js'; + +// TODO:fix this +//@ts-ignore +crypto.getRandomValues = (input) => { + return input; +}; + +// const randomBytes = new Uint8Array(8); +// console.log('inital', randomBytes); +// //@ts-ignore +// let res = crypto.getRandomValues(randomBytes); +// console.log('got res', res); + +const PGPHelper: IPGPHelper = { + async generateKeyPair() { + let keys = await OpenPGP.generate({ keyOptions: { rsaBits: 2048 } }); + return { + privateKeyArmored: keys.privateKey, + publicKeyArmored: keys.publicKey, + }; + }, + + async sign({ message, signingKey }) { + const publicKey = await OpenPGP.convertPrivateKeyToPublicKey(signingKey); + const signature = await OpenPGP.sign(message, publicKey, signingKey, ''); + return signature.replace('\nVersion: openpgp-mobile', ''); + }, + + async pgpEncrypt({ keys, plainText }) { + const encryptedSecret = await OpenPGP.encrypt(plainText, keys.join('\n')); + return encryptedSecret; + }, +}; + +const createUser = async (options: PushApi.user.CreateUserProps) => { + return await PushApi.user.createUserCore(options, PGPHelper); +}; + +const get = async (options: PushApi.AccountEnvOptionsType) => { + return await PushApi.user.get(options); +}; + +const profileUpdate = async (options: PushApi.user.ProfileUpdateProps) => { + return await PushApi.user.profile.updateCore(options, PGPHelper); +}; + +const send = async (options: PushApi.ChatSendOptionsType) => { + return await PushApi.chat.sendCore(options, PGPHelper); +}; + +const approve = async (options: PushApi.chat.ApproveRequestOptionsType) => { + return await PushApi.chat.approveCore(options, PGPHelper); +}; + +const conversationHash = async ( + options: PushApi.ConversationHashOptionsType +) => { + let hash = await PushApi.chat.conversationHash(options); + return hash; +}; + +const chats = async (options: ChatsOptionsType) => { + let chatsList = await PushApi.chat.chatsCore(options, PGPHelper); + return chatsList; +}; + +const latest = async (options: LatestMessagesOptionsType) => { + let latestMsg = await PushApi.chat.latestCore(options, PGPHelper); + return latestMsg; +}; + +const history = async (options: HistoricalMessagesOptionsType) => { + let msg = await PushApi.chat.historyCore(options, PGPHelper); + return msg; +}; + +const createGroup = async (options: ChatCreateGroupType) => { + let group = await PushApi.chat.createGroupCore(options, PGPHelper); + return group; +}; + +const updateGroup = async (options: ChatUpdateGroupType) => { + let updatedGroup = await PushApi.chat.updateGroupCore(options, PGPHelper); + return updatedGroup; +}; + +// checking if ethers works +const genRandomAddress = async () => { + const privateKey = + '25520e97c3f31af3824ff62e350126299997322ff7d340ffd81faa7f84609ef9'; + + // Create an instance of Wallet using the private key + const wallet = new ethers.Wallet(privateKey); + + // Get the address from the wallet + const address = wallet.address; + + return address; +}; + +const profileUpgrade = PushApi.user.auth.update; + +export { + PGPHelper, + genRandomAddress, + createUser, + get, + profileUpdate, + PushApi, + ENV, + conversationHash, + latest, + history, + createGroup, + updateGroup, + chats, + decryptPGPKey, + profileUpgrade, + send, + approve, + Constants, +}; diff --git a/packages/reactnative/src/lib/assets/epnsbot.png b/packages/reactnative/src/lib/assets/epnsbot.png deleted file mode 100644 index 530859af9..000000000 Binary files a/packages/reactnative/src/lib/assets/epnsbot.png and /dev/null differ diff --git a/packages/reactnative/src/lib/assets/epnsbot@2x.png b/packages/reactnative/src/lib/assets/epnsbot@2x.png deleted file mode 100644 index 4e5addec4..000000000 Binary files a/packages/reactnative/src/lib/assets/epnsbot@2x.png and /dev/null differ diff --git a/packages/reactnative/src/lib/assets/epnsbot@3x.png b/packages/reactnative/src/lib/assets/epnsbot@3x.png deleted file mode 100644 index b46ff18bd..000000000 Binary files a/packages/reactnative/src/lib/assets/epnsbot@3x.png and /dev/null differ diff --git a/packages/reactnative/src/lib/assets/frownface.png b/packages/reactnative/src/lib/assets/frownface.png deleted file mode 100644 index 4c226e024..000000000 Binary files a/packages/reactnative/src/lib/assets/frownface.png and /dev/null differ diff --git a/packages/reactnative/src/lib/assets/frownface@2x.png b/packages/reactnative/src/lib/assets/frownface@2x.png deleted file mode 100644 index 3341f443b..000000000 Binary files a/packages/reactnative/src/lib/assets/frownface@2x.png and /dev/null differ diff --git a/packages/reactnative/src/lib/assets/frownface@3x.png b/packages/reactnative/src/lib/assets/frownface@3x.png deleted file mode 100644 index 87c478c69..000000000 Binary files a/packages/reactnative/src/lib/assets/frownface@3x.png and /dev/null differ diff --git a/packages/reactnative/src/lib/components/DownloadHelper.ts b/packages/reactnative/src/lib/components/DownloadHelper.ts deleted file mode 100644 index 29b32aac7..000000000 --- a/packages/reactnative/src/lib/components/DownloadHelper.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* eslint-disable no-useless-escape */ -// @ts-nocheck -import * as FileSystem from 'expo-file-system'; - -// Download Helper Function -const DownloadHelper = { - // To get Temp Save Location - getTempSaveLocation: function (fileURL: string) { - return ( - FileSystem.documentDirectory + - DownloadHelper.getSaveFileName(fileURL, true) - ); - }, - // To get Actual Save Location - getActualSaveLocation: function (fileURL: string) { - return ( - FileSystem.documentDirectory + - DownloadHelper.getSaveFileName(fileURL, false) - ); - }, - // To get Save File Name - getSaveFileName: function (fileURL: string, useTempLocation: boolean) { - // Remove all http, https protocols first - fileURL = fileURL.replace(/(^\w+:|^)\/\//, ''); - - // /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi - // Remove all special characters - fileURL = fileURL.replace(/[`~!@#$%^&*()_|+\-=?;:'",<>\{\}\[\]\\\/]/gi, ''); - - // Remove all but 250 characters - if (fileURL.length > 250) { - fileURL = fileURL.substr(-250); - } - - if (useTempLocation) { - return fileURL + '.temp'; - } else { - return fileURL; - } - }, - // Determine if media is supported video - isMediaSupportedVideo: function (fileURL: string) { - // check if media external embed first - if (DownloadHelper.isMediaExternalEmbed(fileURL)) { - return true; - } else { - // check if mp4 extension - if (fileURL.split('.').pop() === 'mp4') { - return true; - } - } - - // if all else fail - return false; - }, - // check if media is external embed, like youtube, soundcloud, etc - isMediaExternalEmbed: function (fileURL: string) { - return DownloadHelper.isMediaYoutube(fileURL); - }, - // Determine if youtube - isMediaYoutube: function (fileURL: string) { - if (fileURL !== undefined || fileURL !== '') { - const regExp = - /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/; - const match = fileURL.match(regExp); - if (match && match[2] && match[2].length === 11) { - // embed url - // const embedURL = - // 'https://www.youtube.com/embed/' + - // match[2] + - // '?autoplay=1&enablejsapi=1'; - return true; - } - } - - return false; - }, - // Get youtube id - getYoutubeID: function (fileURL: string) { - if (fileURL !== undefined || fileURL !== '') { - const regExp = - /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/; - const match = fileURL.match(regExp); - if (match && match[2] && match[2].length === 11) { - return match[2]; - } - } - - return false; - }, -}; - -export default DownloadHelper; diff --git a/packages/reactnative/src/lib/components/chainDetails/arbitrumSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/arbitrumSVG.tsx deleted file mode 100644 index 7106c3552..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/arbitrumSVG.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from 'react'; -import { SVGProps } from 'react'; - -const ArbitrumSvgComponent = (props: SVGProps<SVGSVGElement>) => ( - <svg - id="Layer_1" - xmlns="http://www.w3.org/2000/svg" - xmlnsXlink="http://www.w3.org/1999/xlink" - x="0px" - y="0px" - viewBox="0 0 1080 1218.5" - xmlSpace="preserve" - {...props} - > - <style type="text/css">{'\n\t.st0{fill:#1B4ADD;}\n'}</style> - <g> - <path - className="st0" - d="M541.8,76.4c2.9,0,5.8,0.8,8.4,2.3l446.1,259.5c5.2,3,8.4,8.6,8.3,14.5l-1.7,516.1c0,6-3.2,11.5-8.4,14.5 l-447.8,256.6c-2.5,1.5-5.5,2.2-8.4,2.2c-2.9,0-5.8-0.8-8.4-2.3L83.8,880.3c-5.2-3-8.4-8.6-8.3-14.5l1.7-516.1 c0-6,3.2-11.5,8.4-14.5L533.4,78.6C535.9,77.1,538.8,76.4,541.8,76.4 M542,1c-15.9-0.1-31.8,4-46.1,12.2L48.1,269.7 c-28.6,16.4-46.2,46.7-46.4,79.7L0,865.5c-0.1,32.9,17.4,63.4,45.8,80L491.9,1205c14.2,8.3,30.1,12.4,46.1,12.5 c15.9,0.1,31.8-4,46.1-12.2l447.8-256.6c28.6-16.4,46.2-46.7,46.4-79.7L1080,353c0.1-32.9-17.4-63.4-45.8-80L588.1,13.5 C573.8,5.2,557.9,1,542,1L542,1z" - /> - <path - className="st0" - d="M632.4,282.3H567c-4.9,0-9.3,3.1-11,7.7L345.8,866.4c-1.4,3.8,1.4,7.8,5.5,7.8h65.4c4.9,0,9.3-3.1,11-7.7 l210.3-576.5C639.2,286.3,636.4,282.3,632.4,282.3z M518,282.3h-65.4c-4.9,0-9.3,3.1-11,7.7L231.4,866.4c-1.4,3.8,1.4,7.8,5.5,7.8 h65.4c4.9,0,9.3-3.1,11-7.7l210.3-576.5C524.9,286.3,522.1,282.3,518,282.3z M602.7,505.8c-1.9-5.1-9.1-5.1-11,0l-34,93.2 c-0.9,2.6-0.9,5.4,0,8l94.7,259.6c1.7,4.6,6.1,7.7,11,7.7h65.4c4.1,0,6.9-4,5.5-7.8L602.7,505.8z M848.6,866.4L659.9,349.1 c-1.9-5.1-9.1-5.1-11,0l-34,93.2c-0.9,2.6-0.9,5.4,0,8l151.9,416.3c1.7,4.6,6.1,7.7,11,7.7h65.4C847.1,874.2,850,870.2,848.6,866.4 z" - /> - </g> - </svg> -); - -export default ArbitrumSvgComponent; diff --git a/packages/reactnative/src/lib/components/chainDetails/bscSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/bscSVG.tsx deleted file mode 100644 index 69b002455..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/bscSVG.tsx +++ /dev/null @@ -1,22 +0,0 @@ -// @ts-nocheck -import * as React from 'react'; -import Svg, {Circle, Path } from 'react-native-svg'; - -const BscSvgComponent = (props: any) => ( - <Svg - width="24" - height="24" - viewBox="0 0 24 24" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <Circle cx="12" cy="12" r="12" fill="#1D1D1D" /> - <Path - d="M8.16193 12L6.58295 13.579L5 12L6.57898 10.421L8.16193 12ZM12 8.16193L14.7085 10.8705L16.2875 9.29148L12 5L7.70852 9.29148L9.2875 10.8705L12 8.16193ZM17.417 10.421L15.8381 12L17.417 13.579L18.996 12L17.417 10.421ZM12 15.8381L9.29148 13.1295L7.7125 14.7085L12 19L16.2875 14.7085L14.7085 13.1295L12 15.8381ZM12 13.579L13.579 12L12 10.421L10.417 12L12 13.579Z" - fill="#F0B90B" - /> - </Svg> -); - -export default BscSvgComponent; diff --git a/packages/reactnative/src/lib/components/chainDetails/ethereumSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/ethereumSVG.tsx deleted file mode 100644 index 6a1b709a2..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/ethereumSVG.tsx +++ /dev/null @@ -1,34 +0,0 @@ -// @ts-nocheck -import * as React from "react" -import Svg, { G, Path } from "react-native-svg" - -const EthereumSvgComponent = (props : any) => ( - <Svg - xmlns="http://www.w3.org/2000/svg" - xmlSpace="preserve" - shapeRendering="geometricPrecision" - textRendering="geometricPrecision" - imageRendering="optimizeQuality" - fillRule="evenodd" - clipRule="evenodd" - viewBox="0 0 784.37 1277.39" - {...props} - > - <G fillRule="nonzero"> - <Path - fill="#343434" - d="m392.07 0-8.57 29.11v844.63l8.57 8.55 392.06-231.75z" - /> - <Path fill="#8C8C8C" d="M392.07 0 0 650.54l392.07 231.75V472.33z" /> - <Path - fill="#3C3C3B" - d="m392.07 956.52-4.83 5.89v300.87l4.83 14.1 392.3-552.49z" - /> - <Path fill="#8C8C8C" d="M392.07 1277.38V956.52L0 724.89z" /> - <Path fill="#141414" d="m392.07 882.29 392.06-231.75-392.06-178.21z" /> - <Path fill="#393939" d="m0 650.54 392.07 231.75V472.33z" /> - </G> - </Svg> -) - -export default EthereumSvgComponent diff --git a/packages/reactnative/src/lib/components/chainDetails/index.tsx b/packages/reactnative/src/lib/components/chainDetails/index.tsx deleted file mode 100644 index dbd6c8e19..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/index.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import EthereumSvg from "./ethereumSVG"; -import PolygonSvg from "./polygonSVG"; -import GraphSvg from "./thegraphSVG"; -import BscSvg from "./bscSVG"; -import OptimismSvg from "./optimismSVG" -import PolygonZKEVMSvg from "./polygonZkEVMSVG"; -import ArbitrumSvgComponent from "./arbitrumSVG"; - -type Network = { - label: string; - Icon: any; -}; - -const networks: Record<string, Network> = { - ETH_TEST_GOERLI: { label: "ETHEREUM GOERLI", Icon: EthereumSvg }, - ETH_MAINNET: { label: "ETHEREUM MAINNET", Icon: EthereumSvg }, - POLYGON_TEST_MUMBAI: { label: "POLYGON MUMBAI", Icon: PolygonSvg }, - POLYGON_MAINNET: { label: "POLYGON MAINNET", Icon: PolygonSvg }, - BSC_TESTNET: { label: "BSC TESTNET", Icon: BscSvg }, - BSC_MAINNET: { label: "BSC MAINNET", Icon: BscSvg }, - OPTIMISM_TESTNET: { label: "OPTIMISM TESTNET", Icon: OptimismSvg }, - 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 }, -}; - -export default networks \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/chainDetails/optimismSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/optimismSVG.tsx deleted file mode 100644 index 900b92514..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/optimismSVG.tsx +++ /dev/null @@ -1,27 +0,0 @@ -// @ts-nocheck -import * as React from 'react'; -import Svg, { Defs, G, Path, Rect } from 'react-native-svg'; - -const OptimismSvgComponent = (props: any) => ( - <Svg - width="24" - height="24" - viewBox="0 0 24 24" - fill="none" - xmlns="http://www.w3.org/2000Sv" - > - <G clip-path="url(#clip0_9390_20606)"> - <Path d="M12 24C18.6274 24 24 18.6274 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24Z" fill="#FF0420"/> - <Path d="M8.50098 15.1872C7.78578 15.1872 7.20018 15.0192 6.74418 14.6832C6.29298 14.3424 6.06738 13.8528 6.06738 13.224C6.06738 13.0896 6.08178 12.9312 6.11058 12.7392C6.18738 12.3072 6.29778 11.7888 6.44178 11.1792C6.84978 9.52799 7.90578 8.70239 9.60498 8.70239C10.0658 8.70239 10.4834 8.77919 10.8482 8.93759C11.213 9.08639 11.501 9.31679 11.7122 9.62399C11.9234 9.92639 12.029 10.2864 12.029 10.704C12.029 10.8288 12.0146 10.9872 11.9858 11.1792C11.8946 11.712 11.789 12.2352 11.6594 12.7392C11.4482 13.56 11.0882 14.1792 10.5698 14.5872C10.0562 14.9904 9.36498 15.1872 8.50098 15.1872ZM8.63058 13.8912C8.96658 13.8912 9.24978 13.7904 9.48498 13.5936C9.72498 13.3968 9.89778 13.0944 9.99858 12.6816C10.1378 12.1152 10.2434 11.6256 10.3154 11.2032C10.3394 11.0784 10.3538 10.9488 10.3538 10.8144C10.3538 10.2672 10.0706 9.99359 9.49938 9.99359C9.16338 9.99359 8.87538 10.0944 8.63538 10.2912C8.40018 10.488 8.23218 10.7904 8.13138 11.2032C8.02098 11.6064 7.91538 12.096 7.80498 12.6816C7.78098 12.8016 7.76658 12.9264 7.76658 13.0608C7.76178 13.6176 8.05458 13.8912 8.63058 13.8912Z" fill="white"/> - <Path d="M12.4463 15.1009C12.3791 15.1009 12.3311 15.0817 12.2927 15.0385C12.2639 14.9905 12.2543 14.9377 12.2639 14.8753L13.5071 9.0193C13.5167 8.9521 13.5503 8.8993 13.6079 8.8561C13.6607 8.8129 13.7183 8.7937 13.7807 8.7937H16.1759C16.8431 8.7937 17.3759 8.9329 17.7791 9.2065C18.1871 9.4849 18.3935 9.8833 18.3935 10.4065C18.3935 10.5553 18.3743 10.7137 18.3407 10.8769C18.1919 11.5681 17.8895 12.0769 17.4287 12.4081C16.9775 12.7393 16.3583 12.9025 15.5711 12.9025H14.3567L13.9439 14.8753C13.9295 14.9425 13.9007 14.9953 13.8431 15.0385C13.7903 15.0817 13.7327 15.1009 13.6703 15.1009H12.4463ZM15.6335 11.6593C15.8879 11.6593 16.1039 11.5921 16.2911 11.4529C16.4831 11.3137 16.6079 11.1169 16.6703 10.8577C16.6895 10.7569 16.6991 10.6657 16.6991 10.5889C16.6991 10.4161 16.6463 10.2817 16.5455 10.1905C16.4447 10.0945 16.2671 10.0465 16.0223 10.0465H14.9423L14.6015 11.6593H15.6335Z" fill="white"/> - </G> - <Defs> - <clipPath id="clip0_9390_20606"> - <Rect width="24" height="24" fill="white"/> - </clipPath> - </Defs> - </Svg> - -); - -export default OptimismSvgComponent; diff --git a/packages/reactnative/src/lib/components/chainDetails/polygonSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/polygonSVG.tsx deleted file mode 100644 index 71e6469a1..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/polygonSVG.tsx +++ /dev/null @@ -1,24 +0,0 @@ -// @ts-nocheck -import * as React from "react" -import Svg, { Path } from "react-native-svg" - -const PolygonSvgComponent = (props : any) => ( - <Svg - xmlns="http://www.w3.org/2000/svg" - viewBox="0 0 38.4 33.5" - style={{ - enableBackground: "new 0 0 38.4 33.5", - }} - xmlSpace="preserve" - {...props} - > - <Path - d="M29 10.2c-.7-.4-1.6-.4-2.4 0L21 13.5l-3.8 2.1-5.5 3.3c-.7.4-1.6.4-2.4 0L5 16.3c-.7-.4-1.2-1.2-1.2-2.1v-5c0-.8.4-1.6 1.2-2.1l4.3-2.5c.7-.4 1.6-.4 2.4 0L16 7.2c.7.4 1.2 1.2 1.2 2.1v3.3l3.8-2.2V7c0-.8-.4-1.6-1.2-2.1l-8-4.7c-.7-.4-1.6-.4-2.4 0L1.2 5C.4 5.4 0 6.2 0 7v9.4c0 .8.4 1.6 1.2 2.1l8.1 4.7c.7.4 1.6.4 2.4 0l5.5-3.2 3.8-2.2 5.5-3.2c.7-.4 1.6-.4 2.4 0l4.3 2.5c.7.4 1.2 1.2 1.2 2.1v5c0 .8-.4 1.6-1.2 2.1L29 28.8c-.7.4-1.6.4-2.4 0l-4.3-2.5c-.7-.4-1.2-1.2-1.2-2.1V21l-3.8 2.2v3.3c0 .8.4 1.6 1.2 2.1l8.1 4.7c.7.4 1.6.4 2.4 0l8.1-4.7c.7-.4 1.2-1.2 1.2-2.1V17c0-.8-.4-1.6-1.2-2.1L29 10.2z" - style={{ - fill: "#8247e5", - }} - /> - </Svg> -) - -export default PolygonSvgComponent diff --git a/packages/reactnative/src/lib/components/chainDetails/polygonZkEVMSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/polygonZkEVMSVG.tsx deleted file mode 100644 index 5fa77721d..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/polygonZkEVMSVG.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import * as React from 'react'; -const PolygonZKEVMSvgComponent = (props: any) => ( - <svg - width={24} - height={24} - viewBox="0 0 24 24" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <g clipPath="url(#clip0_10279_32011)"> - <path - d="M12 24C18.6274 24 24 18.6274 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24Z" - fill="#7B3FE4" - /> - <path - d="M18.4908 6.848L13.2428 3.81333C12.8641 3.6 12.4428 3.48267 12.0054 3.48267C11.5681 3.48267 11.1468 3.6 10.7734 3.81333L5.52542 6.848C5.15209 7.06667 4.83742 7.376 4.61875 7.75467C4.40009 8.128 4.28809 8.55467 4.28809 8.992V15.072C4.29342 15.504 4.40542 15.9253 4.62409 16.2987C4.84275 16.672 5.15209 16.9813 5.52542 17.1947L10.7734 20.2293C11.1468 20.448 11.5734 20.56 12.0108 20.56C12.4481 20.56 12.8694 20.448 13.2481 20.2293L18.4961 17.1947C18.8694 16.976 19.1841 16.6667 19.4028 16.288C19.6214 15.9147 19.7334 15.488 19.7334 15.0507V8.97067C19.7281 8.53867 19.6161 8.11733 19.3974 7.744C19.1734 7.37067 18.8641 7.06133 18.4908 6.848ZM5.52009 8.98667C5.52009 8.768 5.57875 8.55467 5.68542 8.368C5.79209 8.18133 5.95209 8.02133 6.13875 7.91467L11.3868 4.88533C11.5734 4.77867 11.7868 4.72 12.0054 4.72C12.2241 4.72 12.4374 4.77867 12.6241 4.88533L17.8774 7.91467C18.0641 8.02133 18.2188 8.176 18.3254 8.35733C18.4321 8.544 18.4908 8.752 18.4961 8.96533V9.584C18.4961 10.064 18.3041 10.528 17.9628 10.864C17.6214 11.2053 17.1628 11.3973 16.6828 11.3973H7.33875C6.68275 11.3973 6.04809 11.6053 5.52009 12V8.98667ZM18.4908 15.0507C18.4908 15.2693 18.4321 15.4827 18.3254 15.6693C18.2188 15.856 18.0588 16.016 17.8721 16.1227L12.6188 19.152C12.4321 19.2587 12.2188 19.3173 12.0001 19.3173C11.7814 19.3173 11.5681 19.2587 11.3814 19.152L6.13342 16.1227C5.94675 16.016 5.79209 15.8613 5.68542 15.68C5.57875 15.4933 5.52009 15.2853 5.51475 15.072V14.4533C5.51475 13.9733 5.70675 13.5093 6.04809 13.1733C6.38942 12.832 6.84809 12.64 7.32809 12.64H16.6668C17.3228 12.64 17.9574 12.432 18.4854 12.0373V15.0507H18.4908Z" - fill="white" - /> - <path - d="M9.13577 8.67727H10.3358V10.4693H11.5731V8.67727C11.5731 8.35194 11.4451 8.03727 11.2104 7.80261C10.9811 7.57327 10.6664 7.43994 10.3358 7.43994H9.13577C8.81044 7.43994 8.49577 7.56794 8.2611 7.80261C8.03177 8.03194 7.89844 8.34661 7.89844 8.67727V10.4693H9.13577V8.67727Z" - fill="white" - /> - <path - d="M10.3309 15.3601H9.13089V13.5681H7.89355V15.3601C7.89355 15.6854 8.02155 16.0001 8.25622 16.2348C8.48555 16.4641 8.80022 16.5974 9.13089 16.5974H10.3309C10.6562 16.5974 10.9709 16.4694 11.2056 16.2348C11.4349 16.0054 11.5682 15.6908 11.5682 15.3601V13.5681H10.3309V15.3601Z" - fill="white" - /> - <path - d="M14 8.67727H15.2V10.4693H16.4374V8.67727C16.4374 8.35194 16.3094 8.03727 16.0747 7.80261C15.8454 7.57327 15.5307 7.43994 15.2 7.43994H14C13.6747 7.43994 13.36 7.56794 13.1254 7.80261C12.896 8.03194 12.7627 8.34661 12.7627 8.67727V10.4693H14V8.67727Z" - fill="white" - /> - <path - d="M15.2054 15.3601H14.0054V13.5681H12.7681V15.3601C12.7681 15.6854 12.8961 16.0001 13.1307 16.2348C13.3601 16.4641 13.6747 16.5974 14.0054 16.5974H15.2054C15.5307 16.5974 15.8454 16.4694 16.0801 16.2348C16.3094 16.0054 16.4427 15.6908 16.4427 15.3601V13.5681H15.2054V15.3601Z" - fill="white" - /> - </g> - <defs> - <clipPath id="clip0_10279_32011"> - <rect width={24} height={24} fill="white" /> - </clipPath> - </defs> - </svg> -); -export default PolygonZKEVMSvgComponent; diff --git a/packages/reactnative/src/lib/components/chainDetails/thegraphSVG.tsx b/packages/reactnative/src/lib/components/chainDetails/thegraphSVG.tsx deleted file mode 100644 index 479348d37..000000000 --- a/packages/reactnative/src/lib/components/chainDetails/thegraphSVG.tsx +++ /dev/null @@ -1,35 +0,0 @@ -// @ts-nocheck -import * as React from "react" -import Svg, { Circle, Path } from "react-native-svg" - -const GraphSvgComponent = (props) => ( - <Svg - xmlns="http://www.w3.org/2000/svg" - viewBox="10 10 72 72" - style={{ - enableBackground: "new 0 0 96 96", - }} - xmlSpace="preserve" - {...props} - > - <Circle - cx={48} - cy={48} - r={48} - style={{ - fill: "transparent", - }} - /> - <Path - d="M135.3 106.2c-7.1 0-12.8-5.7-12.8-12.8 0-7.1 5.7-12.8 12.8-12.8 7.1 0 12.8 5.7 12.8 12.8 0 7.1-5.7 12.8-12.8 12.8m0-32c10.6 0 19.2 8.6 19.2 19.2s-8.6 19.2-19.2 19.2-19.2-8.6-19.2-19.2 8.6-19.2 19.2-19.2zm18.3 39.4c1.3 1.3 1.3 3.3 0 4.5l-12.8 12.8c-1.3 1.3-3.3 1.3-4.5 0-1.3-1.3-1.3-3.3 0-4.5l12.8-12.8c1.2-1.3 3.3-1.3 4.5 0zm7.4-36.2c0 1.8-1.4 3.2-3.2 3.2-1.8 0-3.2-1.4-3.2-3.2s1.4-3.2 3.2-3.2c1.7 0 3.2 1.4 3.2 3.2z" - style={{ - fillRule: "evenodd", - clipRule: "evenodd", - fill: "#6747ed", - }} - transform="translate(-88 -52)" - /> - </Svg> -) - -export default GraphSvgComponent diff --git a/packages/reactnative/src/lib/components/index.tsx b/packages/reactnative/src/lib/components/index.tsx deleted file mode 100644 index 99db76cbc..000000000 --- a/packages/reactnative/src/lib/components/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './notifications'; \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/loaders/EPNSActivity.tsx b/packages/reactnative/src/lib/components/loaders/EPNSActivity.tsx deleted file mode 100644 index d2f383f0e..000000000 --- a/packages/reactnative/src/lib/components/loaders/EPNSActivity.tsx +++ /dev/null @@ -1,102 +0,0 @@ -// @ts-nocheck -import * as React from 'react'; -import {View, ActivityIndicator, Platform, StyleSheet} from 'react-native'; - -import MaskedView from '@react-native-masked-view/masked-view'; -import {LinearGradient} from 'expo-linear-gradient'; - -import GLOBALS from '../../globals'; - - -export type EPNSActivityProps = { - style?: any; - size?: number | 'small' | 'large' | undefined; - color?: string; -}; - -export const EPNSActivity = (props: EPNSActivityProps) => { - const {style, size, color} = props; - - return ( - <View - style={[ - styles.container, - style, - size === 'small' ? styles.small : styles.big, - ]}> - {Platform.OS === 'android' || color ? ( - <ActivityIndicator - // style={styles.activity} - size={size} - color={color ? color : GLOBALS.COLORS.GRADIENT_THIRD} - /> - ) : ( - <MaskedView - style={styles.maskedView} - maskElement={ - <View style={styles.maskedElementView}> - <ActivityIndicator - // style={styles.activity} - size={size} - color={GLOBALS.COLORS.BLACK} - /> - </View> - }> - <ActivityIndicator - // style={styles.activity} - size={size} - color={GLOBALS.COLORS.WHITE} - /> - <LinearGradient - colors={[ - GLOBALS.COLORS.GRADIENT_PRIMARY, - GLOBALS.COLORS.GRADIENT_SECONDARY, - GLOBALS.COLORS.GRADIENT_THIRD, - ]} - style={[ - styles.fullgradient, - size === 'small' ? styles.small : styles.big, - ]} - start={[0.1, 0.3]} - end={[1, 1]} - /> - </MaskedView> - )} - </View> - ); -}; - -// Styling -const styles = StyleSheet.create({ - container: { - alignSelf: 'center', - alignItems: 'center', - justifyContent: 'flex-end', - }, - small: { - width: 40, - height: 20, - }, - big: { - height: 36, - width: 36, - }, - maskedView: { - flex: 1, - flexDirection: 'row', - height: '100%', - }, - maskedElementView: { - backgroundColor: 'transparent', - flex: 1, - alignItems: 'center', - }, - maskedTitle: { - color: 'black', - fontWeight: 'bold', - }, - fullgradient: { - alignItems: 'flex-end', - width: '100%', - }, -}); diff --git a/packages/reactnative/src/lib/components/loaders/ImageDownloadWithIndicator.tsx b/packages/reactnative/src/lib/components/loaders/ImageDownloadWithIndicator.tsx deleted file mode 100644 index f8aeb0154..000000000 --- a/packages/reactnative/src/lib/components/loaders/ImageDownloadWithIndicator.tsx +++ /dev/null @@ -1,299 +0,0 @@ -import React, {useState, useRef, useEffect} from 'react'; -import { - StyleSheet, - View, - Image, - TouchableWithoutFeedback, - ImageResizeMode, - ImageSourcePropType, -} from 'react-native'; - -import * as FileSystem from 'expo-file-system'; - -import ProgressCircle from 'react-native-progress-circle'; -import { EPNSActivity } from './EPNSActivity'; -import DownloadHelper from '../DownloadHelper'; -import GLOBALS from '../../globals'; - -const MAX_ATTEMPTS = 3; - -const badImgPath = '../../assets/frownface.png'; - -const usePrevious = <T,>(value: T): T | undefined => { - const ref = useRef<T>(); - useEffect(() => { - ref.current = value; - }); - - return ref.current; -}; - -type ImageDownloadWithIndicatorProps = { - style: any; - fileURL?: string; - imgsrc?: ImageSourcePropType; - miniProgressLoader?: boolean; - margin?: number; - resizeMode: ImageResizeMode | string; - onPress?: (arg0: string) => void; -}; - - -export const ImageDownloadWithIndicator = (props: ImageDownloadWithIndicatorProps) => { - const [indicator, setIndicator] = useState(false); - const [downloading, setDownloading] = useState(true); - const [downloadProgress, setDownloadProgress] = useState(0); - const [fileURI, setFileURI] = useState(''); - const [attemptNumber, setAttemptNumber] = useState(0); - const [defaulted, setDefaulted] = useState(false); - - const _isMounted = useRef(false); - - const previousFileUrl = usePrevious(props.fileURL); - - // derived values - const contentContainerStyle: any = {}; - - if (props.margin) { - contentContainerStyle.margin = props.margin; - } - - let modifiedResizeMode = props.resizeMode; - if (defaulted) { - modifiedResizeMode = 'center'; - } - - // To Start Download - const startDownload = async (_fileURL?: string) => { - const localFileTempURI = DownloadHelper.getTempSaveLocation(_fileURL || ''); - - // Create File Download - const downloadResumable = FileSystem.createDownloadResumable( - _fileURL || '', - localFileTempURI, - {}, - dwProg => { - const progress = - dwProg.totalBytesWritten / dwProg.totalBytesExpectedToWrite; - const progressPerc = Number((progress * 100).toFixed(2)); - // console.log('Progress for ' + _fileURL + ': ' + progressPerc); - - if (_isMounted.current) { - setDownloadProgress(progressPerc); - } - }, - ); - - // Initiate - try { - const downloadResult = await downloadResumable.downloadAsync(); - - // console.log(DownloadHelper.getActualSaveLocation(fileURL)); - - // Download completed, move file to actual location - try { - await FileSystem.moveAsync({ - from: downloadResult?.uri || '', - to: DownloadHelper.getActualSaveLocation(_fileURL || ''), - }); - } catch (e) { - console.warn(e); - } - - // Go Back to check and initiate operation - await checkAndInitiateOperation(_fileURL || ''); - } catch (e) { - console.warn(e); - } - }; - - // Check - const checkAndInitiateOperation = async (_fileURL?: string) => { - // Do Nothing, this is already loaded image - if (props.imgsrc) { - setIndicator(false); - setDownloading(false); - setDownloadProgress(100); - // setFileURI(props.imgsrc); - return; - } - - const localFileURI = DownloadHelper.getActualSaveLocation(_fileURL || ''); - const localFileInfo = await FileSystem.getInfoAsync(localFileURI); - - if (localFileInfo.exists) { - if (_isMounted.current) { - setIndicator(false); - setDownloading(false); - setDownloadProgress(100); - setFileURI(localFileURI); - } else { - if (attemptNumber <= MAX_ATTEMPTS) { - if (_isMounted.current) { - setIndicator(false); - setDownloading(true); - setDownloadProgress(0); - setAttemptNumber(attemptNumber + 1); - } - - await startDownload(_fileURL); - } else { - // Image can't be retrieved, Display bad image - // console.log('---> image cannot be retrieved, Display bad image'); - setIndicator(false); - setDownloading(false); - setDownloadProgress(100); - // setFileURI(''); - setDefaulted(true); - } - } - } - }; - - const renderDownloadingView = () => { - return ( - <View style={styles.downloading}> - {props.miniProgressLoader === true ? ( - <EPNSActivity style={styles.activity} size="small" /> - ) : ( - <ProgressCircle - percent={downloadProgress} - radius={20} - borderWidth={20} - color={GLOBALS.COLORS.GRADIENT_SECONDARY} - shadowColor={GLOBALS.COLORS.LIGHT_GRAY} - bgColor={GLOBALS.COLORS.WHITE} - /> - )} - </View> - ); - }; - - const renderBadImageView = () => { - return ( - <Image - style={styles.image} - source={require(badImgPath)} - resizeMode={modifiedResizeMode as ImageResizeMode} - /> - ); - }; - - const renderImageSourceView = (imgSrcPath: ImageSourcePropType) => { - return ( - <Image - style={styles.image} - source={imgSrcPath} - resizeMode={modifiedResizeMode as ImageResizeMode} - /> - ); - }; - - const renderImageView = () => { - // console.log('\n\n\n Debug info: '); - // console.log({ indicator, downloading, defaulted, imgsrc: props.imgsrc, fileURIExists: !!fileURI }); - - if (props.imgsrc) { - return renderImageSourceView(props.imgsrc); - } - - if (indicator) { - return <EPNSActivity style={styles.activity} size="small" />; - } - - if (downloading) { - return renderDownloadingView(); - } - - if (defaulted || !fileURI) { - return renderBadImageView(); - } - - return ( - <Image - style={styles.image} - source={{uri: fileURI }} - resizeMode={props.resizeMode as ImageResizeMode} - /> - ); - } - - // mount - useEffect(() => { - _isMounted.current = true; - checkAndInitiateOperation(props.fileURL); - - return () => { - _isMounted.current = false; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - // fileURL change - useEffect(() => { - // Check for prop change - if (previousFileUrl !== props.fileURL) { - setIndicator(true); - setDownloading(true); - setDownloadProgress(0); - setFileURI(''); - - checkAndInitiateOperation(props.fileURL); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.fileURL]); - - - return ( - <TouchableWithoutFeedback - style={[styles.container]} - onPress={() => { - if (props.onPress) { - props.onPress(fileURI); - } - }} - disabled={!props.onPress ? true : false}> - <View style={[styles.innerContainer, props.style]}> - <View style={[styles.contentContainer, contentContainerStyle]}> - {renderImageView()} - </View> - </View> - </TouchableWithoutFeedback> - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - overflow: 'hidden', - }, - innerContainer: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - overflow: 'hidden', - }, - contentContainer: { - justifyContent: 'center', - alignItems: 'center', - aspectRatio: 1, - width: '100%', - overflow: 'hidden', - }, - downloading: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - width: '100%', - padding: 40, - }, - image: { - flex: 1, - resizeMode: 'cover', - width: '100%', - height: '100%', - overflow: 'hidden', - }, - // this is not present actually in the legacy code - activity: {}, -}); diff --git a/packages/reactnative/src/lib/components/loaders/VideoDownloadWithIndicator.tsx b/packages/reactnative/src/lib/components/loaders/VideoDownloadWithIndicator.tsx deleted file mode 100644 index a1cd6873a..000000000 --- a/packages/reactnative/src/lib/components/loaders/VideoDownloadWithIndicator.tsx +++ /dev/null @@ -1,340 +0,0 @@ -// @ts-nocheck -import React, { Component } from "react"; -import { - StyleSheet, - View, - Image, - TouchableWithoutFeedback, -} from "react-native"; -import * as FileSystem from "expo-file-system"; - -import Video from "react-native-video"; -import YouTube from "react-native-youtube"; - -import ProgressCircle from "react-native-progress-circle"; -import { EPNSActivity } from "./EPNSActivity"; - -import DownloadHelper from "../DownloadHelper"; - -import GLOBALS from "../../globals"; - -const MAX_ATTEMPTS = 3; - - -export type VideoDownloadWithIndicatorProps = { - style: any; - fileURL: string; - resizeMode?: string; - youTubeAPIKey: string; -}; - -type VideoDownloadWithIndicatorState = { - indicator: boolean; - downloading: boolean; - downloadProgress: number; - fileURI: string; - attemptNumber: number; - defaulted: boolean; -}; - - -class VideoDownloadWithIndicator extends Component <VideoDownloadWithIndicatorProps, VideoDownloadWithIndicatorState> { - // CONSTRUCTOR - constructor(props: VideoDownloadWithIndicatorProps) { - super(props); - - this.state = { - indicator: false, - downloading: true, - downloadProgress: 0, - fileURI: "", - - attemptNumber: 0, - defaulted: false, - }; - - // Set Mounted - this._isMounted = false; - } - - // COMPONENT MOUNTED - componentDidMount() { - // Start Operation - this._isMounted = true; - this.checkAndInitiateOperation(this.props.fileURL); - } - - // COMPONENT UPDATED - componentDidUpdate(prevProps) { - // Check for prop change - if (this.props.fileURL !== prevProps.fileURL) { - this.setState({ - indicator: true, - downloading: true, - downloadProgress: 0, - fileURI: "", - }); - - this.checkAndInitiateOperation(this.props.fileURL); - } - } - - // COMPONENT UNMOUNTED - componentWillUnmount() { - this._isMounted = false; - } - - // FUNCTIONS - // Check - checkAndInitiateOperation = async (fileURL) => { - if (DownloadHelper.isMediaExternalEmbed(fileURL)) { - // Do Nothing, this is already loaded media - this.setState({ - indicator: false, - downloading: false, - downloadProgress: "100%", - fileURI: fileURL, - }); - - return; - } - - const localFileURI = DownloadHelper.getActualSaveLocation(fileURL); - const localFileInfo = await FileSystem.getInfoAsync(localFileURI); - - if (localFileInfo.exists) { - if (this._isMounted) { - this.setState({ - indicator: false, - downloading: false, - downloadProgress: 100, - fileURI: localFileURI, - }); - } - - // console.log("File Exists on: |" + localFileURI + "|"); - } else { - if (this.state.attemptNumber <= MAX_ATTEMPTS) { - if (this._isMounted) { - this.setState({ - indicator: false, - downloading: true, - downloadProgress: 0, - attemptNumber: this.state.attemptNumber + 1, - }); - } - - await this.startDownload(fileURL); - } else { - // Image can't be retrieved, Display bad image - this.setState({ - indicator: false, - downloading: false, - downloadProgress: "100%", - fileURI: require('../../assets/frownface.png'), - defaulted: true, - }); - } - } - }; - - // To Start Download - startDownload = async (fileURL) => { - const localFileTempURI = DownloadHelper.getTempSaveLocation(fileURL); - - // Create File Download - const downloadResumable = FileSystem.createDownloadResumable( - fileURL, - localFileTempURI, - {}, - (dwProg) => { - const progress = - dwProg.totalBytesWritten / dwProg.totalBytesExpectedToWrite; - const progressPerc = Number((progress * 100).toFixed(2)); - //console.log("Progress for " + fileURL + ": " + progressPerc); - - if (this._isMounted) { - this.setState({ - downloadProgress: progressPerc, - }); - } - } - ); - - // Initiate - try { - const { uri } = await downloadResumable.downloadAsync(); - // console.log("MOVING"); - // console.log(uri); - // console.log(DownloadHelper.getActualSaveLocation(fileURL)); - - // Download completed, move file to actual location - try { - await FileSystem.moveAsync({ - from: uri, - to: DownloadHelper.getActualSaveLocation(fileURL), - }); - } catch (e) { - console.warn(e); - } - - // Go Back to check and initiate operation - await this.checkAndInitiateOperation(fileURL); - } catch (e) { - console.warn(e); - } - }; - - // on video bufferring - onBuffer = (response) => { - // console.log('onBuffer: ', response); - }; - - // When Errored - videoError = (error) => { - // console.log("Error on playback" + error); - - this.setState({ - indicator: false, - downloading: false, - downloadProgress: "100%", - fileURI: require('../../assets/frownface.png'), - defaulted: true, - }); - }; - - // handle on press - onPress = () => { - // console.log("here"); - this.player.presentFullscreenPlayer(); - - if (this.props.onPress) { - this.props.onPress(); - } - }; - - // RENDER - render() { - const { - style, - miniProgressLoader, - margin, - resizeMode, - } = this.props; - - const contentContainerStyle = {}; - if (margin) { - contentContainerStyle.margin = margin; - } - - let modifiedResizeMode = resizeMode; - if (this.state.defaulted) { - modifiedResizeMode = "center"; - } - - return ( - <TouchableWithoutFeedback - style={[styles.container]} - onPress={() => { - this.onPress(this.state.fileURI); - }} - disabled={true} - > - <View style={[styles.innerContainer, style]}> - <View style={[styles.contentContainer, contentContainerStyle]}> - {this.state.indicator ? ( - <EPNSActivity style={styles.activity} size="small" /> - ) : this.state.downloading ? ( - <View style={styles.downloading}> - {miniProgressLoader === true ? ( - <EPNSActivity style={styles.activity} size="small" /> - ) : ( - <ProgressCircle - percent={this.state.downloadProgress} - radius={20} - borderWidth={20} - color={GLOBALS.COLORS.GRADIENT_SECONDARY} - shadowColor={GLOBALS.COLORS.LIGHT_GRAY} - bgColor={GLOBALS.COLORS.WHITE} - ></ProgressCircle> - )} - </View> - ) : this.state.defaulted === true ? ( - <Image - style={styles.image} - source={require('../../assets/frownface.png')} - resizeMode={modifiedResizeMode} - /> - ) : DownloadHelper.isMediaExternalEmbed(this.state.fileURI) === - false ? ( - <Video - source={{ uri: `${this.state.fileURI}` }} - ref={(ref) => { - this.player = ref; - }} - onBuffer={this.onBuffer} - onError={this.videoError} - style={styles.backgroundVideo} - resizeMode="cover" - controls={true} - paused={true} - allowFullScreen={true} - /> - ) : ( - <YouTube - videoId={DownloadHelper.getYoutubeID(this.state.fileURI)} - apiKey={this.props.youTubeAPIKey} - play={false} - fullscreen={false} - loop={false} - controls={1} - onReady={(e) => this.setState({ isReady: true })} - onChangeState={(e) => this.setState({ status: e.state })} - onChangeQuality={(e) => this.setState({ quality: e.quality })} - onError={(e) => this.setState({ error: e.error })} - style={styles.backgroundVideo} - /> - )} - </View> - </View> - </TouchableWithoutFeedback> - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - overflow: "hidden", - }, - innerContainer: { - flex: 1, - height: "100%", - overflow: "hidden", - }, - contentContainer: { - justifyContent: "center", - alignItems: "center", - aspectRatio: 1, - width: "100%", - overflow: "hidden", - }, - downloading: { - flex: 1, - justifyContent: "center", - alignItems: "center", - width: "100%", - padding: 40, - }, - backgroundVideo: { - position: "absolute", - top: 0, - left: 0, - bottom: 0, - right: 0, - }, -}); - -export { - VideoDownloadWithIndicator -} \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/loaders/index.tsx b/packages/reactnative/src/lib/components/loaders/index.tsx deleted file mode 100644 index 113de8946..000000000 --- a/packages/reactnative/src/lib/components/loaders/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export * from './EPNSActivity'; -export * from './ImageDownloadWithIndicator'; -export * from './VideoDownloadWithIndicator'; diff --git a/packages/reactnative/src/lib/components/notifications/index.tsx b/packages/reactnative/src/lib/components/notifications/index.tsx deleted file mode 100644 index 3f0d15b4e..000000000 --- a/packages/reactnative/src/lib/components/notifications/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './notification'; \ 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 deleted file mode 100644 index bbc064056..000000000 --- a/packages/reactnative/src/lib/components/notifications/notification.tsx +++ /dev/null @@ -1,427 +0,0 @@ -import React from 'react'; -import { - View, Text, TouchableOpacity, StyleSheet, - Linking, Image, TouchableWithoutFeedback -} from 'react-native'; - -import Modal from 'react-native-modal'; -import device from 'react-native-device-detection'; -import moment from 'moment'; - -import { ParseText } from '../parsetext'; -import GLOBALS from '../../globals'; -import { extractTimeStamp } from './utils'; -import DownloadHelper from '../DownloadHelper'; -import chainDetails from '../chainDetails'; - -import { ImageDownloadWithIndicator, VideoDownloadWithIndicator } from '../loaders'; - - -// ================= 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" | "ARBITRUMONE_MAINNET" | "ARBITRUM_TESTNET" | "THE_GRAPH" | undefined; - -const botImageLocalPath = '../../assets/epnsbot.png'; - -export type NotificationProps = { - notificationTitle: string; - notificationBody: string; - app: string; - icon: string; - appbot?: string; - image: string; - cta?: string; - url?: string; - chainName: chainNameType; - onImagePreview?: (arg0: string) => void; - youTubeAPIKey: string; -}; - - -export const Notification : React.FC<NotificationProps> = ({ - notificationTitle = '', - notificationBody = '', - cta = '', - app = '', - icon = '', - appbot = '', - image = '', - url = '', - chainName, - youTubeAPIKey, - onImagePreview -}) => { - const ctaEnabled = Boolean(cta); - - const { - originalBody: parsedBody, - timeStamp -} = extractTimeStamp(notificationBody || ''); - - // store the image to be displayed in this state variable - const [ isVisible, setIsVisible ] = React.useState(false); - - const internalBot = appbot === '1'; - - const ChainIcon = chainName && chainDetails[chainName] ? chainDetails[chainName].Icon : null; - - // Finally mark if the device is a tablet or a phone - let contentInnerStyle = {}; - let contentImgStyle = {}; - let contentMsgImgStyle = {}; - - let contentVidStyle = {}; - let contentMsgVidStyle = {}; - - // let bgVidStyle = {}; - // let contentYoutubeStyle = { - // marginBottom: 12 - // } - let contentBodyStyle = {}; - let containMode = 'contain'; - - if (device.isTablet) { - // Change the style to better suit tablet - contentInnerStyle = { - flexDirection: 'row', - alignItems: 'center', - }; - - contentImgStyle = { - width: '25%', - aspectRatio: 1, - borderRadius: 10, - paddingRight: 20, - }; - - contentMsgImgStyle = { - margin: 20, - marginRight: 5, - borderRadius: 10, - borderWidth: 0, - }; - - // contentYoutubeStyle = { - // width: '25%', - // aspectRatio: 1, - // borderRadius: 10, - // paddingRight: 20, - // margin: 20, - // marginRight: 10 - // } - - contentVidStyle = { - width: '25%', - aspectRatio: 1, - margin: 20, - marginRight: 10 - } - - contentBodyStyle = { - flex: 1, - }; - - contentMsgVidStyle = { - width: '100%', - } - - // bgVidStyle = { - // borderRadius: 10, - // } - - containMode = 'cover'; - } - - const ctaStyles = { - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - backgroundColor: GLOBALS.COLORS.GRADIENT_SECONDARY, - borderWidth: 1, - borderRadius: GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS - }; - - if(ctaEnabled){ - ctaStyles['borderColor'] = GLOBALS.COLORS.GRADIENT_SECONDARY; - ctaStyles['borderWidth'] = 1; // this is 1 in web - ctaStyles['borderRadius'] = GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS; - } - - // to check valid url - const validURL = (str: string) => { - const pattern = new RegExp( - "^(https?:\\/\\/)?" + // protocol - "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name - "((\\d{1,3}\\.){3}\\d{1,3}))" + // OR ip (v4) address - "(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path - "(\\?[;&a-z\\d%_.~+=-]*)?" + // query string - "(\\#[-a-z\\d_]*)?$", - "i" - ); // fragment locator - return !!pattern.test(str); - }; - - const onPress = (url:string) => { - // TODO: fixTS - // eslint-disable-next-line no-constant-condition - if (validURL(url) || 1) { - // console.log("OPENING URL ", url); - // Bypassing the check so that custom app domains can be opened - Linking.canOpenURL(url).then(supported => { - if (supported) { - Linking.openURL(url); - } - }); - } - }; - - return ( - <TouchableOpacity - style={[styles.container]} - onPress={() => onPress(cta)} - disabled={!ctaEnabled}> - <View style={[styles.inner, ctaStyles]}> - <View style={styles.header}> - <View style={styles.appInfo}> - <TouchableOpacity - style={[styles.appLink]} - disabled={!url} - onPress={() => onPress(url)} - > - <ImageDownloadWithIndicator - style={styles.appicon} - fileURL={internalBot ? "" : icon} - imgsrc={internalBot ? require(botImageLocalPath) : ''} - miniProgressLoader={true} - margin={2} - resizeMode="contain" - /> - - <Text style={styles.apptext} numberOfLines={1}> - {app} - </Text> - </TouchableOpacity> - </View> - - - {ChainIcon ? ( - <View style={styles.networkIcon}> - <ChainIcon /> - </View> - ) : null} - </View> - - <View style={[styles.content]}> - <View style={[ contentInnerStyle]}> - {!image ? null : DownloadHelper.isMediaSupportedVideo(image) ? ( - <View style={[styles.contentVid, contentVidStyle]}> - <VideoDownloadWithIndicator - style={[styles.msgVid, contentMsgVidStyle]} - fileURL={image} - resizeMode={containMode} - youTubeAPIKey={youTubeAPIKey} - /> - </View> - ) : ( - <View style={[styles.contentImg, contentImgStyle]}> - <ImageDownloadWithIndicator - style={[styles.msgImg, contentMsgImgStyle]} - fileURL={image} - resizeMode={containMode} - onPress={(fileURI: string) => { - if (onImagePreview) { - // means List view gallery method is present. - onImagePreview(fileURI); - } else { - // use Item's own view method - setIsVisible(true); - } - }} - /> - </View> - )} - - <View style={[styles.contentBody, contentBodyStyle]}> - {!notificationTitle ? null : ( - <Text style={[styles.msgSub]}>{notificationTitle}</Text> - )} - <View style={styles.msg}> - {/* The entire content of the main component */} - <ParseText - title={ - parsedBody - .replace(/\\n/g, '\n') - .replace(/\//g, '') || "" - } - fontSize={13} - /> - {/* The entire content of the main component */} - </View> - - {!timeStamp ? null : ( - <View style={styles.timestampOuter}> - <Text style={styles.timestamp}> - {moment - .utc(parseInt(timeStamp) * 1000) - .local() - .format('DD MMM YYYY | hh:mm A')} - </Text> - </View> - )} - </View> - </View> - </View> - - {/* when an image is clicked on make it fulll screen */} - <Modal animationIn="fadeIn" animationOut="fadeOut" isVisible={isVisible}> - <TouchableWithoutFeedback onPress={()=> setIsVisible(false)}> - <Image - style={styles.overlayImage} - source={{uri: image}} - /> - </TouchableWithoutFeedback> - </Modal> - {/* when an image is clicked on make it fulll screen */} - </View> - </TouchableOpacity> - ); -}; - -// ================= Define styled components -// / Styling -const styles = StyleSheet.create({ - backgroundVideo: { - position: 'relative', - width: '100%', - aspectRatio: 1, - top: 0, - bottom: 0, - right: 0, - }, - container: { - marginVertical: 15, - marginHorizontal: 20 - }, - inner: { - margin: 1, - overflow: 'hidden', - borderRadius: GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS, - }, - header: { - width: '100%', - paddingVertical: 8, - paddingHorizontal: 10, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - borderBottomWidth: 1, - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - }, - appInfo: { - flex: 1, - alignItems: 'flex-start', - }, - appLink: { - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center', - }, - appicon: { - flex: 0, - justifyContent: 'center', - alignItems: 'center', - borderRadius: 5, - height: 24, - width: 24, - aspectRatio: 1, - marginRight: 5, - overflow: 'hidden', - backgroundColor: GLOBALS.COLORS.SLIGHT_GRAY, - }, - apptext: { - marginRight: 10, - marginLeft: 5, - fontSize: 14, - color: GLOBALS.COLORS.BLACK, - fontWeight: '400', - }, - networkIcon: { - fontSize: 9, - color: 'blue', - fontWeight: '300', - height: 18, - width: 18 - }, - appsecret: { - width: 16, - height: 16, - borderRadius: 16, - }, - content: { - backgroundColor: GLOBALS.COLORS.WHITE, - padding: 12, // as per Web - paddingBottom: 0 - }, - contentLoader: { - margin: 20, - }, - contentVid: { - width: '100%', - marginBottom: 12 - }, - msgVid: { - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - borderBottomWidth: 1, - }, - contentImg: { - width: '100%', - aspectRatio: 2, - marginBottom: 12 - }, - msgImg: { - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - borderBottomWidth: 1, - resizeMode: 'contain', - }, - contentBody: { - paddingHorizontal: 0, - }, - msgSub: { - fontSize: 18, - fontWeight: '400', - color: GLOBALS.COLORS.BLACK, - paddingVertical: 0, - }, - msg: { - paddingTop: 5, - paddingBottom: 15, - }, - timestampOuter: { - display: 'flex', - justifyContent: 'center', - alignSelf: 'flex-end', - paddingBottom: 8, - paddingHorizontal: 15, - marginRight: -20, - overflow: 'hidden', - }, - timestamp: { - fontWeight: 'bold', - fontSize: 10, - color: '#808080', - }, - image: { - flex: 1, - resizeMode: 'cover', - width: '100%', - height: '100%', - overflow: 'hidden', - marginBottom: 12 // same as web - }, - overlayImage: { - flex: 1, - resizeMode: 'contain', - borderRadius: 20, - overflow: 'hidden', - } -}); diff --git a/packages/reactnative/src/lib/components/notifications/utils.ts b/packages/reactnative/src/lib/components/notifications/utils.ts deleted file mode 100644 index 78c1f3936..000000000 --- a/packages/reactnative/src/lib/components/notifications/utils.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @description Parse the contents of the markdown version of the notification body - * @param message the notification body we wish to parse - * @returns - */ - export const FormatBody = (message: string) => { - // firstly replace all new line content of the text with <br /> - // in order to parse it as HTML i.e "\n\n" => "<br /><br />" - const parsedNewLine = message.replace(/\n/g, "<br />"); - // remove leading slashes from text i.e \alex => alex - const removedLeadingSlash = parsedNewLine.replace(/^\\/g, ""); - - return removedLeadingSlash; - } - - -/** - * @description parse and extract the timestamp from the body of the notification and remove the text from the body - * @param notificationBody the text which would represent the body of the notification - * @returns - */ - export function extractTimeStamp(notificationBody: string): { - notificationBody: string; - timeStamp: string; - originalBody: string; - } { - const parsedBody = { - notificationBody: FormatBody(notificationBody), - timeStamp: "", - originalBody: notificationBody, - }; - const matches = notificationBody.match(/\[timestamp:(.*?)\]/); - if (matches) { - parsedBody.timeStamp = matches[1] || ''; - const textWithoutTimeStamp = notificationBody.replace( - / *\[timestamp:[^)]*\] */g, - "" - ); - parsedBody.notificationBody = FormatBody(textWithoutTimeStamp); - parsedBody.originalBody = textWithoutTimeStamp; - } - return parsedBody; - } \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/parsetext/index.tsx b/packages/reactnative/src/lib/components/parsetext/index.tsx deleted file mode 100644 index 76ef60f5c..000000000 --- a/packages/reactnative/src/lib/components/parsetext/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './parsetext'; \ No newline at end of file diff --git a/packages/reactnative/src/lib/components/parsetext/parsetext.tsx b/packages/reactnative/src/lib/components/parsetext/parsetext.tsx deleted file mode 100644 index a97bc8978..000000000 --- a/packages/reactnative/src/lib/components/parsetext/parsetext.tsx +++ /dev/null @@ -1,227 +0,0 @@ -// @ts-nocheck -// TODO: fixTS -import * as React from 'react'; -import { StyleSheet, View, Linking, Platform } from 'react-native'; -import ParsedText from 'react-native-parsed-text'; - -import GLOBALS from '../../globals'; - - -export function ParseText(props: any) { - const { - style, - title, - fontSize, - textStyle, - } = props; - - const handleUrlPress = (matchingString: string, matchIndex:number/*: number*/) => { - const pattern = /\[([^:]+):([^\]]+)\]/i; - const match = matchingString.match(pattern) || []; - - const midComponent = `${match[2]}`; - const url = midComponent.substr(midComponent.indexOf('||') + 2); - - Linking.openURL(url); - }; - - const handleAppSettings = () => { - if (Platform.OS === 'ios') { - Linking.openURL('app-settings:'); - } - }; - - const renderStyles = (matchingString: string, matches: string[]) => { - // matches => ["[@michel:5455345]", "@michel", "5455345"] - const pattern = /\[([^:]+):([^\]]+)\]/i; - const match = matchingString.match(pattern) || []; - - return `${match[2]}`; - }; - - const renderThreeStyles = (matchingString: string, matches: string[]) => { - // matches => ["[@michel:5455345]", "@michel", "5455345"] - const pattern = /\[([^:]+):([^\]]+)\]/i; - const match = matchingString.match(pattern) || []; - - const midComponent = `${match[2]}`; - const midText = midComponent.substr(0, midComponent.indexOf('||')); - return midText; - }; - - const TextUpdatedStyle = { - fontSize: fontSize - } - - const parseSettings = [ - { - pattern: /\[(u):([^\]]+)\]/i, // url - style: [styles.primary, styles.bold, styles.italics, styles.underline], - onPress: handleUrlPress, - renderText: renderThreeStyles - }, - { - pattern: /\[(ub):([^\]]+)\]/i, // url - style: [styles.secondary, styles.bold, styles.italics, styles.underline], - onPress: handleUrlPress, - renderText: renderThreeStyles - }, - { - pattern: /\[(ut):([^\]]+)\]/i, // url - style: [styles.third, styles.bold, styles.italics, styles.underline], - onPress: handleUrlPress, - renderText: renderThreeStyles - }, - { - pattern: /\[(up):([^\]]+)\]/i, // url - style: [styles.primary, styles.italics, styles.underline], - onPress: handleUrlPress, - renderText: renderThreeStyles - }, - { - pattern: /\[(d):([^\]]+)\]/i, // default or primary gradient color - style: [styles.primary, styles.bold], - renderText: renderStyles - }, - { - pattern: /\[(s):([^\]]+)\]/i, // secondary gradient color - style: [styles.secondary, styles.bold], - renderText: renderStyles - }, - { - pattern: /\[(t):([^\]]+)\]/i, // third gradient color - style: [styles.third, styles.bold], - renderText: renderStyles - }, - { - pattern: /\[(e):([^\]]+)\]/i, // error - style: [styles.error, styles.bold], - renderText: renderStyles - }, - { - pattern: /\[(b):([^\]]+)\]/i, // bold - style: styles.bold, - renderText: renderStyles - }, - { - pattern: /\[(i):([^\]]+)\]/i, // italics - style: styles.italics, - renderText: renderStyles - }, - { - pattern: /\[(bi):([^\]]+)\]/i, // bolditalics - style: [styles.bold, styles.italics], - renderText: renderStyles - }, - { - pattern: /\[(w):([^\]]+)\]/i, // white - style: [styles.white], - renderText: renderStyles - }, - { - pattern: /\[(wb):([^\]]+)\]/i, // whitebold - style: [styles.white, styles.bold], - renderText: renderStyles - }, - { - pattern: /\[(mg):([^\]]+)\]/i, // midgray - style: [styles.midgray], - renderText: renderStyles - }, - { - pattern: /\[(dg):([^\]]+)\]/i, // darkgray - style: [styles.darkgray], - renderText: renderStyles - }, - { - pattern: /\[(ddg):([^\]]+)\]/i, // darker gray - style: [styles.darkergray], - renderText: renderStyles - }, - ]; - - if (Platform.OS === 'ios') { - parseSettings.push( - { - pattern: /\[(appsettings):([^\]]+)\]/i, - style: [styles.link, styles.bold, styles.italics, styles.underline], - onPress: handleAppSettings, - renderText: renderStyles - } - ); - } - else if (Platform.OS === 'android') { - parseSettings.push( - { - pattern: /\[(appsettings):([^\]]+)\]/i, - style: [styles.bold], - renderText: renderStyles - } - ); - } - - return ( - <View style = {[ styles.container, style ]}> - <ParsedText - style = {[ styles.text, TextUpdatedStyle, textStyle ]} - parse = {parseSettings} - childrenProps={{allowFontScaling: false}} - > - {title} - </ParsedText> - </View> - ); - -} - - -// Styling -const styles = StyleSheet.create({ - container: { - }, - name: { - color: GLOBALS.COLORS.SUBLIME_RED - }, - username: { - color: GLOBALS.COLORS.GRADIENT_SECONDARY - }, - text: { - color: GLOBALS.COLORS.BLACK - }, - primary: { - color: GLOBALS.COLORS.GRADIENT_PRIMARY, - }, - secondary: { - color: GLOBALS.COLORS.GRADIENT_SECONDARY, - }, - third: { - color: GLOBALS.COLORS.GRADIENT_THIRD, - }, - error: { - color: GLOBALS.COLORS.SUBLIME_RED, - }, - white: { - color: GLOBALS.COLORS.WHITE, - }, - midgray: { - color: GLOBALS.COLORS.MID_GRAY, - }, - darkgray: { - color: GLOBALS.COLORS.DARK_GRAY, - }, - darkergray: { - color: GLOBALS.COLORS.DARKER_GRAY, - }, - link: { - color: GLOBALS.COLORS.GRADIENT_PRIMARY, - }, - underline: { - textDecorationLine: 'underline', - }, - bold: { - fontWeight: 'bold' - }, - italics: { - fontStyle: 'italic' - } -}); \ No newline at end of file diff --git a/packages/reactnative/src/lib/globals.ts b/packages/reactnative/src/lib/globals.ts deleted file mode 100644 index 07389689a..000000000 --- a/packages/reactnative/src/lib/globals.ts +++ /dev/null @@ -1,137 +0,0 @@ -export default { - LINKS: { - APPBOT_NAME: 'App Bot', - APP_WEBSITE: 'https://epns.io', - DEV_EPNS_SERVER: 'https://backend-kovan.epns.io/apis', - PROD_EPNS_SERVER: 'https://backend-kovan.epns.io/apis', - METAMASK_LINK_STAGING: 'https://metamask.app.link/dapp/staging-app.epns.io', - METAMASK_LINK_PROD: 'https://metamask.app.link/dapp/staging-app.epns.io', - DEEPLINK_URL: 'https://metamask.app.link/dapp/staging-app.epns.io', - CNS_ENDPOINT: - 'https://unstoppabledomains.com/api/v1/resellers/udtesting/domains', - - ENDPOINT_AUTHTOKEN: '/pushtokens/authtoken', - ENDPOINT_REGISTER_NO_AUTH: '/pushtokens/register_no_auth', - ENDPOINT_REGISTER: '/pushtokens/register', - ENDPOINT_GET_FEEDS: '/feeds/get_feeds', - ENDPOINT_GET_SPAM_FEEDS: '/feeds/get_spam_feeds', - ENDPOINT_FETCH_CHANNELS: '/channels/fetch_channels', - ENDPOINT_FETCH_SUBSCRIPTION: '/channels/is_user_subscribed', - ENDPOINT_SUBSCRIBE_OFFCHAIN: '/channels/subscribe_offchain', - ENDPOINT_UNSUBSCRIBE_OFFCHAIN: '/channels/unsubscribe_offchain', - }, - - // For Async Storage --> Represents Key and some Constants - STORAGE: { - IS_SIGNED_IN: 'IsUserSignedIn', - SIGNED_IN_TYPE: 'SignedInType', - FIRST_SIGN_IN: 'FirstSignInByUser', - USER_LOCKED: 'UserLocked', - PASSCODE_ATTEMPTS: 'MaxPasscodeAttempts', - - STORED_WALLET_OBJ: 'StoredWalletObject', - ENCRYPTED_PKEY: 'EncryptedPrivateKey', - - HASHED_PASSCODE: 'HashedPasscode', - - PUSH_TOKEN: 'PushToken', - PUSH_TOKEN_TO_REMOVE: 'PushTokenToRemove', - PUSH_TOKEN_SERVER_SYNCED: 'PushTokenServerSynced', - PUSH_BADGE_COUNT: 'PushBadgeCount', - PUSH_BADGE_COUNT_PREVIOUS: 'PreviousPushBadgeCount', - }, - - CONSTANTS: { - CRED_TYPE_WALLET: 'TypeWallet', - CRED_TYPE_PRIVATE_KEY: 'TypePrivateKey', - - NULL_EXCEPTION: 'NULL', - - MAX_PASSCODE_ATTEMPTS: 5, - - PUSH_TYPE_NORMAL_MSG: 1, - PUSH_TYPE_ENCRYPTED_MSG: 2, - - FEED_ITEMS_TO_PULL: 20, - - STATUS_BAR_HEIGHT: 60, - }, - - ADJUSTMENTS: { - SCREEN_GAP_HORIZONTAL: 10, - SCREEN_GAP_VERTICAL: 10, - - DEFAULT_BIG_RADIUS: 10, - DEFAULT_MID_RADIUS: 8, - FEED_ITEM_RADIUS: 8, - }, - - COLORS: { - PRIMARY: 'rgba(27.0, 150.0, 227.0, 1.0)', - - LINKS: 'rgba(20.0, 126.0, 251.0, 1.0)', - - GRADIENT_PRIMARY: 'rgba(226.0, 8.0, 128.0, 1.0)', - GRADIENT_SECONDARY: 'rgba(53.0, 197.0, 243.0, 1.0)', - GRADIENT_THIRD: 'rgba(103.0, 76.0, 159.0, 1.0)', - - TRANSPARENT: 'transparent', - - WHITE: 'rgba(255.0, 255.0, 255.0, 1.0)', - DARK_WHITE: 'rgba(255.0, 255.0, 255.0, 0.75)', - MID_WHITE: 'rgba(255.0, 255.0, 255.0, 0.5)', - LIGHT_WHITE: 'rgba(255.0, 255.0, 255.0, 0.25)', - - SLIGHTER_GRAY: 'rgba(250.0, 250.0, 250.0, 1)', - SLIGHT_GRAY: 'rgba(231.0, 231.0, 231.0, 1)', - LIGHT_GRAY: 'rgba(225.0, 225.0, 225.0, 1)', - MID_GRAY: 'rgba(200.0, 200.0, 200.0, 1)', - DARK_GRAY: 'rgba(160.0, 160.0, 160.0, 1)', - DARKER_GRAY: 'rgba(100.0, 100.0, 100.0, 1)', - - LIGHT_BLACK_TRANS: 'rgba(0.0, 0.0, 0.0, 0.1)', - SEMI_MID_BLACK_TRANS: 'rgba(0.0, 0.0, 0.0, 0.25)', - MID_BLACK_TRANS: 'rgba(0.0, 0.0, 0.0, 0.5)', - DARK_BLACK_TRANS: 'rgba(0.0, 0.0, 0.0, 0.75)', - BLACK: 'rgba(0.0, 0.0, 0.0, 1.0)', - - CONFIRM_GREEN: 'rgba(50.0, 205.0, 50.0, 1.0)', - - CONFIRM: 'rgba(34.0, 139.0, 34.0, 1.0)', - WARNING: 'rgba(255.0, 153.0, 0.0, 1.0)', - - SUBLIME_RED: 'rgba(237.0, 59.0, 72.0, 1.0)', - BADGE_RED: 'rgba(208.0, 44.0, 30.0, 1.0)', - LIGHT_MAROON: 'rgba(159.0, 0.0, 0.0, 1.0)', - LIGHTER_MAROON: 'rgba(129.0, 0.0, 0.0, 1.0)', - }, - SCREENS: { - WELCOME: 'Welcome', - SIGNIN: 'SignIn', - SIGNINADVANCE: 'SignInAdvance', - BIOMETRIC: 'Biometric', - PUSHNOTIFY: 'PushNotify', - SETUPCOMPLETE: 'SetupComplete', - TABS: 'Tabs', - SETTINGS: 'Settings', - SPLASH: 'Splash', - FEED: 'Feed', - CHANNELS: 'Channels', - SPAM: 'Spam', - SAMPLEFEED: 'SampleFeed', - NEWWALLETSIGNIN: 'NewWalletSignIn', - }, - APP_AUTH_STATES: { - INITIALIZING: 1, - ONBOARDING: 2, - ONBOARDED: 3, - AUTHENTICATED: 4, - }, - AUTH_STATE: { - INITIALIZING: 'INITIALIZING', - ONBOARDING: 'ONBOARDING', - ONBOARDED: 'ONBOARDED', - AUTHENTICATED: 'AUTHENTICATED', - }, - }; - \ No newline at end of file diff --git a/packages/reactnative/src/lib/index.tsx b/packages/reactnative/src/lib/index.tsx deleted file mode 100644 index 099b463e3..000000000 --- a/packages/reactnative/src/lib/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './components'; \ No newline at end of file diff --git a/packages/reactnative/test-setup.ts b/packages/reactnative/test-setup.ts deleted file mode 100644 index 9f28ad211..000000000 --- a/packages/reactnative/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-native/extend-expect'; diff --git a/packages/reactnative/tsconfig.build.json b/packages/reactnative/tsconfig.build.json new file mode 100644 index 000000000..999d3f3c8 --- /dev/null +++ b/packages/reactnative/tsconfig.build.json @@ -0,0 +1,5 @@ + +{ + "extends": "./tsconfig", + "exclude": ["example"] +} diff --git a/packages/reactnative/tsconfig.json b/packages/reactnative/tsconfig.json index 6d076c06d..392fa464b 100644 --- a/packages/reactnative/tsconfig.json +++ b/packages/reactnative/tsconfig.json @@ -1,20 +1,27 @@ { - "extends": "../../tsconfig.base.json", "compilerOptions": { - "jsx": "react-jsx", - "allowJs": true, + "baseUrl": "./", + "paths": { + "@push/react-native-sdk": ["./src/index"] + }, + "allowUnreachableCode": false, + "allowUnusedLabels": false, "esModuleInterop": true, - "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, - "strict": true, + "jsx": "react", + "lib": ["esnext"], + "module": "esnext", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - } - ] + "noImplicitUseStrict": false, + "noStrictGenericChecks": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "esnext" + } } diff --git a/packages/reactnative/tsconfig.lib.json b/packages/reactnative/tsconfig.lib.json deleted file mode 100644 index b1ada63f2..000000000 --- a/packages/reactnative/tsconfig.lib.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "types": ["node"], - "jsx": "react-native" - }, - "exclude": ["**/*.spec.ts", "**/*.spec.tsx", "test-setup.ts"], - "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] -} diff --git a/packages/restapi/README.md b/packages/restapi/README.md index 93c9f0f87..ccca693d7 100644 --- a/packages/restapi/README.md +++ b/packages/restapi/README.md @@ -18,6 +18,50 @@ This package gives access to Push Protocol (Push Nodes) APIs. Visit [Developer D - [Push core contract address](#push-core-contract-address) - [Push communicator contract address](#push-communicator-contract-address) - [SDK Features](#sdk-features) + - [PushNotification Class](#pushnotification-class) + - [Initialize](#initialize) + - [Fetch Inbox Or Spam notifications](#fetch-inbox-or-spam-notifications) + - [Fetch user subscriptions](#fetch-user-subscriptions) + - [Subscribe to a channel](#subscribe-to-a-channel) + - [Unsubscribe to a channel](#unsubscribe-to-a-channel) + - [Channel information](#channel-information) + - [Search Channels](#search-channels) + - [Get Subscribers Of A Channel](#get-subscribers-of-a-channel) + - [Send a notification](#send-a-notification) + - [Create a channel](#create-a-channel) + - [Update channel information](#update-channel-information) + - [Verify a channel](#verify-a-channel) + - [Create channel Setting (WIP)](#create-channel-setting) + - [Get delegators information](#get-delegators-information) + - [Add delegator to a channel or alias](#add-delegator-to-a-channel-or-alias) + - [Remove delegator from a channel or alias](#remove-delegator-from-a-channel-or-alias) + - [Alias Information](#alias-information) + - [Stream Notifications](#stream-notifications) + - [PushChat Class](#pushchat-class) + - [Initialize](#initialize) + - [Fetch Info](#fetch-info) + - [Fetch Profile Info](#fetch-profile-info) + - [Update Profile Info](#update-profile-info) + - [Fetch Latest Chat](#fetch-latest-chat) + - [Fetch Chat History](#fetch-chat-history) + - [Send Message](#send-message) + - [Accept Chat Request](#accept-chat-request) + - [Reject Chat Request](#reject-chat-request) + - [Block Chat User](#block-chat-user) + - [Unblock Chat User](#unblock-chat-user) + - [Create Group](#create-group) + - [Fetch Group Info](#fetch-group-info) + - [Fetch Group Permission](#fetch-group-permissions) + - [Update Group](#update-group) + - [Add To Group](#add-to-group) + - [Remove From Group](#remove-from-group) + - [Join Group](#join-group) + - [Leave Group](#leave-group) + - [Reject Group Joining Request](#reject-group-joining-request) + - [Fetch Encryption Info](#fetch-encryption-info) + - [Update Encryption](#update-encryption) + - [Stream Chat Events](#stream-chat-events) + - [Stream Chat Ops Events](#stream-chat-ops-events) - [For Video](#for-video) - [Instance Variables](#instance-variables) - [peerInstance](#peerinstance) @@ -54,51 +98,6 @@ This package gives access to Push Protocol (Push Nodes) APIs. Visit [Developer D - [Fetching list of user spaces](#fetching-list-of-user-spaces) - [Fetching list of user space requests](#fetching-list-of-user-space-requests) - [Fetching list of trending spaces](#fetching-list-of-trending-spaces) - - [PushChat Class](#pushapi-class) - - [Initialize](#initialize) - - [Fetch Info](#fetch-info) - - [Fetch Profile Info](#fetch-profile-info) - - [Update Profile Info](#update-profile) - - [Fetch Latest Chat](#fetch-latest-chat) - - [Fetch Chat History](#fetch-chat-history) - - [Send Message](#send-message) - - [Accept Chat Request](#accept-chat-request) - - [Reject Chat Request](#reject-chat-request) - - [Block Chat User](#block-chat-user) - - [Unblock Chat User](#unblock-chat-user) - - [Create Group](#create-group) - - [Fetch Group Info](#fetcg-group-info) - - [Fetch Group Permission](#fetch-group-permissions) - - [Update Group Info](#update-group-info) - - [Add To Group](#add-to-group) - - [Remove From Group](#remove-from-group) - - [Join Group](#join-group) - - [Leave Group](#leave-group) - - [Reject Group Joining Request](#reject-group-joining-request) - - [Fetch Encryption Info](#fetch-encryption-info) - - [Update Encryption](#update-encryption) - - [Stream Chat Events](#stream-chat-events) - - [Stream Chat Ops Events](#stream-chat-ops-events) - - [PushNotification Class](#pushnotification-class) - - [Initialize](#initialize) - - [Fetch Inbox Or Spam notifications](#fetch-inbox-or-spam-notifications) - - [Fetch user subscriptions](#fetch-user-subscriptions) - - [Subscribe to a channel](#subscribe-to-a-channel) - - [Unsubscribe to a channel](#unsubscribe-to-a-channel) - - [Channel information](#channel-information) - - [Search Channels](#search-channels) - - [Get Subscribers Of A Channel](#get-subscribers-of-a-channel) - - [Send a notification](#send-a-notification) - - [Create a channel](#create-a-channel) - - [Update channel information](#update-channel-information) - - [Verify a channel](#verify-a-channel) - - [Create channel Setting (WIP)](#create-channel-setting-(wip)) - - [Get delegators information](#get-delegators-information) - - [Add delegator to a channel or alias](#add-delegator-to-a-channel-or-alias) - - [Remove delegator from a channel or alias](#remove-delegator-from-a-channel-or-alias) - - [Alias Information](#alias-information) - - [Stream Notifications](#stream-notifications) - # How to use in your app? ## Installation @@ -783,7 +782,7 @@ export interface Rules { --- -### **To check user access of a token gated group** +### **To check user access of a token gated space** ```typescript @@ -2587,23 +2586,63 @@ const spaces = await PushAPI.space.trending({ ```typescript // Initialize PushAPI class instance -const userAlice = await PushAPI.initialize(signer); +const userAlice = await PushAPI.initialize(signer, { + env: ENV.LOCAL, + streamOptions: { + listen: [STREAM.PROFILE, STREAM.ENCRYPTION, ...Object.values(STREAM)], + filter: { + channels: ['Channel1', 'Channel2'], + chats: ['Chat1', 'Chat2'] + }, + connection: { + auto: true, + retries: 3 + }, + raw: true, + enabled: true + }, + }); ``` -| Param | Type | Default | Remarks | -| ------------------------ | -------------------------------------- | ------------- | -------------------------------------------------------------------------------------- | -| `signer` | `SignerType` | - | EthersV5 or Viem Signer | -| `options` \* | `PushAPIInitializeProps` | - | Optional configuration properties for initializing the PushAPI. | -| `options.env` \* | `ENV` | `staging` | API env - 'prod', 'staging', 'dev' | -| `options.progressHook`\* | `(progress: ProgressHookType) => void` | - | A callback function to receive progress updates during initialization. | -| `options.account` \* | `string` | - | The account to associate with the PushAPI. If not provided, it is derived from signer. | -| `options.version` \* | `string` | `ENC_TYPE_V3` | The encryption version to use for the PushAPI | -| `options.versionMeta` \* | `{ NFTPGP_V1 ?: password: string }` | - | Metadata related to the encryption version, including a password if needed. | -| `options.autoUpgrade` \* | `boolean` | `true` | If `true`, upgrades encryption keys to latest encryption version | -| `options.origin` \* | `string` | - | Specify origin or source while creating a Push Profile | + + +## Parameters + +| Param | Type | Default | Remarks | +| --------------------------------------- | ------------------------------------------------- | ------------- | -------------------------------------------------------------------------------------- | +| `signer` | `SignerType` | - | EthersV5 or Viem Signer. | +| `options` \* | `PushAPIInitializeProps` | - | Optional configuration properties for initializing the PushAPI. | +| `options.env` \* | `ENV` | `staging` | API env - 'prod', 'staging', 'dev'. | +| `options.progressHook`\* | `(progress: ProgressHookType) => void` | - | A callback function to receive progress updates during initialization. | +| `options.account` \* | `string` | - | The account to associate with the PushAPI. If not provided, it is derived from signer. | +| `options.version` \* | `string` | `ENC_TYPE_V3` | The encryption version to use for the PushAPI. | +| `options.versionMeta` \* | `{ NFTPGP_V1 ?: password: string }` | - | Metadata related to the encryption version, including a password if needed. | +| `options.autoUpgrade` \* | `boolean` | `true` | If `true`, upgrades encryption keys to the latest encryption version. | +| `options.origin` \* | `string` | - | Specify origin or source while creating a Push Profile. | +| `options.streamOptions` \* | `PushStreamInitializeProps` | - | Configuration options for the stream. | +| `options.streamOptions.listen` \* | `STREAM[]` | - | Specifies which streams to listen to. | +| `options.streamOptions.filter` \* | `{ channels?: string[]; chats?: string[]; }` | - | Specifies which channels or chats to filter for. | +| `options.streamOptions.connection` \* | `{ auto?: boolean; retries?: number; }` | - | Connection settings, including auto-connect and number of retries. | +| `options.streamOptions.raw` \* | `boolean` | - | If set to `true`, will provide raw stream data. | +| `options.streamOptions.enabled` \* | `boolean` | - | Specifies if the stream is enabled or not. | + + + \* - Optional +## STREAM Options + +| Option | Value | +|-----------------------|------------------------| +| `PROFILE` | `STREAM.PROFILE` | +| `ENCRYPTION` | `STREAM.ENCRYPTION` | +| `NOTIF` | `STREAM.NOTIF` | +| `NOTIF_OPS` | `STREAM.NOTIF_OPS` | +| `CHAT` | `STREAM.CHAT` | +| `CHAT_OPS` | `STREAM.CHAT_OPS` | + + --- ### **Fetch Info** @@ -5088,6 +5127,7 @@ const aliceUpdateEncryption = await userAlice.encryption.update( --- <details> <summary><b>Expected response (Chat Message Stream)</b></summary> + ```tsx { "event": "chat.message", @@ -5121,6 +5161,7 @@ const aliceUpdateEncryption = await userAlice.encryption.update( } ``` </details> + --- <details> @@ -5162,7 +5203,7 @@ const aliceUpdateEncryption = await userAlice.encryption.update( --- <details> - <summary><b>Expected response (Greoup Chat Message)</b></summary> + <summary><b>Expected response (Group Chat Message)</b></summary> ```tsx { @@ -5465,23 +5506,51 @@ const aliceUpdateEncryption = await userAlice.encryption.update( ```typescript // Initialize PushAPI class instance -const userAlice = await PushAPI.initialize(signer); +const userAlice = await PushAPI.initialize(signer, { + env: ENV.LOCAL, + streamOptions: { raw: true }, + }); ``` -| Param | Type | Default | Remarks | -| ------------------------ | -------------------------------------- | ------------- | -------------------------------------------------------------------------------------- | -| `signer` | `SignerType` | - | EthersV5 or Viem Signer | -| `options` \* | `PushAPIInitializeProps` | - | Optional configuration properties for initializing the PushAPI. | -| `options.env` \* | `ENV` | `staging` | API env - 'prod', 'staging', 'dev' | -| `options.progressHook`\* | `(progress: ProgressHookType) => void` | - | A callback function to receive progress updates during initialization. | -| `options.account` \* | `string` | - | The account to associate with the PushAPI. If not provided, it is derived from signer. | -| `options.version` \* | `string` | `ENC_TYPE_V3` | The encryption version to use for the PushAPI | -| `options.versionMeta` \* | `{ NFTPGP_V1 ?: password: string }` | - | Metadata related to the encryption version, including a password if needed. | -| `options.autoUpgrade` \* | `boolean` | `true` | If `true`, upgrades encryption keys to latest encryption version | -| `options.origin` \* | `string` | - | Specify origin or source while creating a Push Profile | + + +## Parameters + +| Param | Type | Default | Remarks | +| --------------------------------------- | ------------------------------------------------- | ------------- | -------------------------------------------------------------------------------------- | +| `signer` | `SignerType` | - | EthersV5 or Viem Signer. | +| `options` \* | `PushAPIInitializeProps` | - | Optional configuration properties for initializing the PushAPI. | +| `options.env` \* | `ENV` | `staging` | API env - 'prod', 'staging', 'dev'. | +| `options.progressHook`\* | `(progress: ProgressHookType) => void` | - | A callback function to receive progress updates during initialization. | +| `options.account` \* | `string` | - | The account to associate with the PushAPI. If not provided, it is derived from signer. | +| `options.version` \* | `string` | `ENC_TYPE_V3` | The encryption version to use for the PushAPI. | +| `options.versionMeta` \* | `{ NFTPGP_V1 ?: password: string }` | - | Metadata related to the encryption version, including a password if needed. | +| `options.autoUpgrade` \* | `boolean` | `true` | If `true`, upgrades encryption keys to the latest encryption version. | +| `options.origin` \* | `string` | - | Specify origin or source while creating a Push Profile. | +| `options.streamOptions` \* | `PushStreamInitializeProps` | - | Configuration options for the stream. | +| `options.streamOptions.listen` \* | `STREAM[]` | - | Specifies which streams to listen to. | +| `options.streamOptions.filter` \* | `{ channels?: string[]; chats?: string[]; }` | - | Specifies which channels or chats to filter for. | +| `options.streamOptions.connection` \* | `{ auto?: boolean; retries?: number; }` | - | Connection settings, including auto-connect and number of retries. | +| `options.streamOptions.raw` \* | `boolean` | - | If set to `true`, will provide raw stream data. | +| `options.streamOptions.enabled` \* | `boolean` | - | Specifies if the stream is enabled or not. | + + + \* - Optional +## STREAM Options + +| Option | Value | +|-----------------------|------------------------| +| `PROFILE` | `STREAM.PROFILE` | +| `ENCRYPTION` | `STREAM.ENCRYPTION` | +| `NOTIF` | `STREAM.NOTIF` | +| `NOTIF_OPS` | `STREAM.NOTIF_OPS` | +| `CHAT` | `STREAM.CHAT` | +| `CHAT_OPS` | `STREAM.CHAT_OPS` | + + --- ### **Fetch Inbox Or Spam notifications** @@ -6328,7 +6397,7 @@ const searchResult = await userAlice.channel.search("push") --- -### **Get a channel's subscribers** +### **Get Subscribers Of A Channel** ```tsx // fetches subscribers of a channel @@ -6451,7 +6520,7 @@ const createChannelRes = await userAlice.channel.create({name: channelName, desc --- -### **Update a channel's information** +### **Update channel information** ```tsx // updates channel info @@ -6509,11 +6578,11 @@ const verifyChannelRes = await userAlice.channel.verify(channelToBeVerified) --- -### **Create channel Setting (WIP)** +### **Create channel Setting** ```tsx // creates channel settings -const createChannelSettingRes = userAlice.channel.settings([{ type: 0, default: 1, description: 'marketing' }, {type: 2, default: 10, description: 'loan liquidation threshold', data: {upper: 100, lower: 5}}]) +const createChannelSettingRes = userAlice.channel.settings([{ type: 0, default: 1, description: 'marketing' }, {type: 2, default: 10, description: 'loan liquidation threshold', data: {upper: 100, lower: 5, enabled: true, ticker: 5}}]) ``` @@ -6526,6 +6595,8 @@ const createChannelSettingRes = userAlice.channel.settings([{ type: 0, default: | description | string | - | A description of the setting. | | data.upper* | number | - | Valid for slider type only. The upper limit for the setting. | | data.lower* | number | - | Valid for slider type only. The lower limit for the setting. | +| data.enabled* | boolean | - | Valid for slider type only. If the settting should be enabled by default. | +| data.ticker* | number | - | Valid for slider type only. Offset for slider values | <details> <summary><b>Expected response (Create Channel Setting)</b></summary> @@ -6571,7 +6642,7 @@ const delegatorsInfo = userAlice.channel.delegate.get() --- -### **Add delegator to a channel/alias** +### **Add delegator to a channel or alias** ```tsx // adds a delegate @@ -6597,7 +6668,7 @@ const addDelegatorRes = userAlice.channel.delegate.add(delegatorAddressInCAIP) --- -### **Remove delegator from a channel/alias** +### **Remove delegator from a channel or alias** ```tsx // removes a delegate diff --git a/packages/restapi/src/lib/chat/approveRequest.ts b/packages/restapi/src/lib/chat/approveRequest.ts index 44f0c8c02..7084bb32b 100644 --- a/packages/restapi/src/lib/chat/approveRequest.ts +++ b/packages/restapi/src/lib/chat/approveRequest.ts @@ -4,16 +4,17 @@ import Constants from '../constants'; import { EnvOptionsType, SignerType } from '../types'; import { approveRequestPayload, - sign, - getConnectedUserV2, IApproveRequestPayload, getAccountAddress, getWallet, getUserDID, + getConnectedUserV2Core, + PGPHelper, + IPGPHelper, } from './helpers'; import * as CryptoJS from 'crypto-js'; -interface ApproveRequestOptionsType extends EnvOptionsType { +export interface ApproveRequestOptionsType extends EnvOptionsType { /** * Chat request sender address */ @@ -34,6 +35,13 @@ interface ApproveRequestOptionsType extends EnvOptionsType { */ export const approve = async ( options: ApproveRequestOptionsType +): Promise<string> => { + return await approveCore(options, PGPHelper); +}; + +export const approveCore = async ( + options: ApproveRequestOptionsType, + pgpHelper: IPGPHelper ): Promise<string> => { const { status = 'Approved', @@ -60,7 +68,12 @@ export const approve = async ( isGroup = false; } - const connectedUser = await getConnectedUserV2(wallet, pgpPrivateKey, env); + const connectedUser = await getConnectedUserV2Core( + wallet, + pgpPrivateKey, + env, + pgpHelper + ); let fromDID = await getUserDID(senderAddress, env); let toDID = await getUserDID(address, env); @@ -76,7 +89,7 @@ export const approve = async ( }; const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString(); - const signature: string = await sign({ + const signature: string = await pgpHelper.sign({ message: hash, signingKey: connectedUser.privateKey!, }); diff --git a/packages/restapi/src/lib/chat/chats.ts b/packages/restapi/src/lib/chat/chats.ts index 20cc2624b..349a7d627 100644 --- a/packages/restapi/src/lib/chat/chats.ts +++ b/packages/restapi/src/lib/chat/chats.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { getAPIBaseUrls, isValidETHAddress } from '../helpers'; import Constants, { ENV } from '../constants'; import { IFeeds } from '../types'; -import { getInboxLists, getUserDID, addDeprecatedInfo } from './helpers'; +import { getInboxLists, getUserDID, addDeprecatedInfo, IPGPHelper, PGPHelper } from './helpers'; export type ChatsOptionsType = { account: string; @@ -28,7 +28,12 @@ export type ChatsOptionsType = { /** * Return the latest message from all wallet addresses you have talked to. This can be used when building the inbox page. */ + export const chats = async (options: ChatsOptionsType): Promise<IFeeds[]> => { + return await chatsCore(options,PGPHelper) +} + +export const chatsCore = async (options: ChatsOptionsType, pgpHelper: IPGPHelper): Promise<IFeeds[]> => { const { account, pgpPrivateKey, diff --git a/packages/restapi/src/lib/chat/conversationHash.ts b/packages/restapi/src/lib/chat/conversationHash.ts index 85a1aef50..9541fcb82 100644 --- a/packages/restapi/src/lib/chat/conversationHash.ts +++ b/packages/restapi/src/lib/chat/conversationHash.ts @@ -7,9 +7,8 @@ import { getConversationHashService, getUserDID } from './helpers'; * All chat messages are stored on IPFS. This function will return the latest message's CID (Content Identifier on IPFS). * Whenever a new message is sent or received, this CID will change. */ -export const conversationHash = async ( - options: ConversationHashOptionsType -) => { + +export const conversationHash = async(options: ConversationHashOptionsType) => { const { conversationId, account, env = Constants.ENV.PROD } = options || {}; try { if (!isValidETHAddress(account)) { diff --git a/packages/restapi/src/lib/chat/createGroup.ts b/packages/restapi/src/lib/chat/createGroup.ts index 4d451d3fe..3632603e5 100644 --- a/packages/restapi/src/lib/chat/createGroup.ts +++ b/packages/restapi/src/lib/chat/createGroup.ts @@ -5,12 +5,13 @@ import { EnvOptionsType, GroupDTO, SignerType, Rules } from '../types'; import { ICreateGroupRequestPayload, createGroupPayload, - sign, createGroupRequestValidator, getWallet, getUserDID, - getConnectedUserV2, + IPGPHelper, + PGPHelper, validateScheduleDates, + getConnectedUserV2Core, } from './helpers'; import * as CryptoJS from 'crypto-js'; @@ -35,8 +36,13 @@ export interface ChatCreateGroupType extends EnvOptionsType { rules?: Rules | null; } -export const createGroup = async ( - options: ChatCreateGroupType +export const createGroup = async (options: ChatCreateGroupType) => { + return await createGroupCore(options, PGPHelper); +}; + +export const createGroupCore = async ( + options: ChatCreateGroupType, + pgpHelper: IPGPHelper ): Promise<GroupDTO> => { const { account = null, @@ -89,7 +95,12 @@ export const createGroup = async ( const convertedMembers = await Promise.all(convertedMembersPromise); const convertedAdmins = await Promise.all(convertedAdminsPromise); - const connectedUser = await getConnectedUserV2(wallet, pgpPrivateKey, env); + const connectedUser = await getConnectedUserV2Core( + wallet, + pgpPrivateKey, + env, + pgpHelper + ); const bodyToBeHashed = { groupName: groupName, @@ -108,7 +119,7 @@ export const createGroup = async ( }; const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString(); - const signature: string = await sign({ + const signature: string = await pgpHelper.sign({ message: hash, signingKey: connectedUser.privateKey!, }); diff --git a/packages/restapi/src/lib/chat/helpers/crypto.ts b/packages/restapi/src/lib/chat/helpers/crypto.ts index 43021a45d..3637855b0 100644 --- a/packages/restapi/src/lib/chat/helpers/crypto.ts +++ b/packages/restapi/src/lib/chat/helpers/crypto.ts @@ -59,13 +59,41 @@ export const encryptAndSign = async ({ signature: string; sigType: string; encType: string; +}> => { + return await encryptAndSignCore({ + plainText, + keys, + privateKeyArmored, + secretKey, + pgpHelper: PGP.PGPHelper, + }); +}; + +export const encryptAndSignCore = async ({ + plainText, + keys, + privateKeyArmored, + secretKey, + pgpHelper, +}: { + plainText: string; + keys: Array<string>; + privateKeyArmored: string; + secretKey: string; + pgpHelper: PGP.IPGPHelper; +}): Promise<{ + cipherText: string; + encryptedSecret: string; + signature: string; + sigType: string; + encType: string; }> => { const cipherText: string = AES.aesEncrypt({ plainText, secretKey }); - const encryptedSecret = await PGP.pgpEncrypt({ + const encryptedSecret = await pgpHelper.pgpEncrypt({ plainText: secretKey, keys: keys, }); - const signature: string = await PGP.sign({ + const signature: string = await pgpHelper.sign({ message: cipherText, signingKey: privateKeyArmored, }); @@ -88,7 +116,26 @@ export const signMessageWithPGP = async ({ signature: string; sigType: string; }> => { - const signature: string = await PGP.sign({ + return await signMessageWithPGPCore ({ + message, + privateKeyArmored, + pgpHelper: PGP.PGPHelper, + }); +}; + +export const signMessageWithPGPCore = async ({ + message, + privateKeyArmored, + pgpHelper +}: { + message: string; + privateKeyArmored: string; + pgpHelper: PGP.IPGPHelper; +}): Promise<{ + signature: string; + sigType: string; +}> => { + const signature: string = await pgpHelper.sign({ message: message, signingKey: privateKeyArmored, }); @@ -180,6 +227,28 @@ export const getEncryptedRequest = async ( env: ENV, group: GroupDTO | null, secretKey: string +): Promise<IEncryptedRequest> => { + return await getEncryptedRequestCore( + receiverAddress, + senderCreatedUser, + message, + isGroup, + env, + group, + secretKey, + PGP.PGPHelper + ); +}; + +export const getEncryptedRequestCore = async ( + receiverAddress: string, + senderCreatedUser: IConnectedUser, + message: string, + isGroup: boolean, + env: ENV, + group: GroupDTO | null, + secretKey: string, + pgpHelper: PGP.IPGPHelper ): Promise<IEncryptedRequest> => { if (!isGroup) { const receiverCreatedUser: IUser = await get({ @@ -198,9 +267,10 @@ export const getEncryptedRequest = async ( }); // If the user is being created here, that means that user don't have a PGP keys. So this intent will be in plaintext - const { signature } = await signMessageWithPGP({ + const { signature } = await signMessageWithPGPCore({ message: message, privateKeyArmored: senderCreatedUser.privateKey!, + pgpHelper: pgpHelper, }); return { @@ -217,9 +287,10 @@ export const getEncryptedRequest = async ( '-----BEGIN PGP PUBLIC KEY BLOCK-----' ) ) { - const { signature } = await signMessageWithPGP({ + const { signature } = await signMessageWithPGPCore({ message: message, privateKeyArmored: senderCreatedUser.privateKey!, + pgpHelper: pgpHelper, }); return { @@ -229,12 +300,13 @@ export const getEncryptedRequest = async ( signature: signature, }; } else { - const { cipherText, encryptedSecret, signature } = await encryptAndSign( + const { cipherText, encryptedSecret, signature } = await encryptAndSignCore( { plainText: message, keys: [receiverCreatedUser.publicKey, senderCreatedUser.publicKey], privateKeyArmored: senderCreatedUser.privateKey!, secretKey, + pgpHelper: pgpHelper, } ); return { @@ -247,9 +319,10 @@ export const getEncryptedRequest = async ( } } else if (group) { if (group.isPublic) { - const { signature } = await signMessageWithPGP({ + const { signature } = await signMessageWithPGPCore({ message: message, privateKeyArmored: senderCreatedUser.privateKey!, + pgpHelper: pgpHelper, }); return { message: message, @@ -261,11 +334,12 @@ export const getEncryptedRequest = async ( const publicKeys: string[] = group.members.map( (member) => member.publicKey ); - const { cipherText, encryptedSecret, signature } = await encryptAndSign({ + const { cipherText, encryptedSecret, signature } = await encryptAndSignCore({ plainText: message, keys: publicKeys, privateKeyArmored: senderCreatedUser.privateKey!, secretKey, + pgpHelper: pgpHelper, }); return { message: cipherText, diff --git a/packages/restapi/src/lib/chat/helpers/payloadHelper.ts b/packages/restapi/src/lib/chat/helpers/payloadHelper.ts index 16d8eaaf4..b322a8e00 100644 --- a/packages/restapi/src/lib/chat/helpers/payloadHelper.ts +++ b/packages/restapi/src/lib/chat/helpers/payloadHelper.ts @@ -1,4 +1,5 @@ import { isValidETHAddress, walletToPCAIP10 } from '../../helpers'; +import { getEncryptedRequestCore } from './crypto'; import { IConnectedUser, GroupDTO, @@ -11,9 +12,12 @@ import { } from '../../types'; import { getEncryptedRequest } from './crypto'; import { ENV } from '../../constants'; +import { IPGPHelper, PGPHelper } from './pgp'; import * as AES from './aes'; -import { MessageObj } from '../../types/messageTypes'; import { sign } from './pgp'; +import { MessageObj } from '../../types/messageTypes'; + + import * as CryptoJS from 'crypto-js'; export interface ISendMessagePayload { fromDID: string; @@ -88,33 +92,58 @@ export const sendMessagePayload = async ( messageType: string, group: GroupDTO | null, env: ENV +): Promise<ISendMessagePayload> => { + return await sendMessagePayloadCore( + receiverAddress, + senderCreatedUser, + messageObj, + messageContent, + messageType, + group, + env, + PGPHelper, + ); +}; + + +export const sendMessagePayloadCore = async ( + receiverAddress: string, + senderCreatedUser: IConnectedUser, + messageObj: MessageObj | string, + messageContent: string, + messageType: string, + group: GroupDTO | null, + env: ENV, + pgpHelper: IPGPHelper, ): Promise<ISendMessagePayload> => { const isGroup = !isValidETHAddress(receiverAddress); const secretKey: string = AES.generateRandomSecret(15); const { message: encryptedMessageContent, signature: deprecatedSignature } = - await getEncryptedRequest( + await getEncryptedRequestCore( receiverAddress, senderCreatedUser, messageContent, isGroup, env, group, - secretKey + secretKey, + pgpHelper ); const { message: encryptedMessageObj, encryptionType, aesEncryptedSecret, - } = await getEncryptedRequest( + } = await getEncryptedRequestCore( receiverAddress, senderCreatedUser, JSON.stringify(messageObj), isGroup, env, group, - secretKey + secretKey, + pgpHelper ); const body: ISendMessagePayload = { @@ -144,7 +173,7 @@ export const sendMessagePayload = async ( encryptedSecret: body.encryptedSecret, }; const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString(); - const signature: string = await sign({ + const signature: string = await pgpHelper.sign({ message: hash, signingKey: senderCreatedUser.privateKey!, }); diff --git a/packages/restapi/src/lib/chat/helpers/pgp.ts b/packages/restapi/src/lib/chat/helpers/pgp.ts index 024c5cd79..7d23e6591 100644 --- a/packages/restapi/src/lib/chat/helpers/pgp.ts +++ b/packages/restapi/src/lib/chat/helpers/pgp.ts @@ -1,5 +1,47 @@ import * as openpgp from 'openpgp'; +interface IPGPHelper{ + generateKeyPair(): Promise<{ privateKeyArmored: string; publicKeyArmored: string }>; + sign ({ message, signingKey }: { message: string; signingKey: string }): Promise<string>; + pgpEncrypt ({ plainText, keys }: { plainText: string; keys: Array<string> }): Promise<string>; +} + +const PGPHelper:IPGPHelper = { + async generateKeyPair(){ + const keys = await openpgp.generateKey({ + type: 'rsa', + rsaBits: 2048, + userIDs: [{ name: '', email: '' }] + }) + return { + privateKeyArmored: keys.privateKey, + publicKeyArmored: keys.publicKey + } + }, + + async sign ({ message, signingKey }): Promise<string> { + const messageObject: openpgp.Message<string> = await openpgp.createMessage({ text: message }) + const privateKey: openpgp.PrivateKey = await openpgp.readPrivateKey({ armoredKey: signingKey }) + return <string>await openpgp.sign({ message: messageObject, signingKeys: privateKey, detached: true }) + }, + + async pgpEncrypt ({ plainText, keys }): Promise<string> { + const pgpKeys: openpgp.Key[] = []; + + for(let i = 0; i < keys.length; i++) { + pgpKeys.push(await openpgp.readKey({ armoredKey: keys[i] })); + } + const message: openpgp.Message<string> = await openpgp.createMessage({ text: plainText }); + const encrypted: string = <string>await openpgp.encrypt({ + message: message, + encryptionKeys: pgpKeys, + }); + return encrypted; + }, +} + +export {IPGPHelper, PGPHelper} + export const generateKeyPair = async (): Promise<{ privateKeyArmored: string; publicKeyArmored: string }> => { const keys = await openpgp.generateKey({ type: 'rsa', diff --git a/packages/restapi/src/lib/chat/helpers/user.ts b/packages/restapi/src/lib/chat/helpers/user.ts index 1c8cf2ff5..06a9a9d4b 100644 --- a/packages/restapi/src/lib/chat/helpers/user.ts +++ b/packages/restapi/src/lib/chat/helpers/user.ts @@ -1,8 +1,8 @@ import Constants, { ENV } from '../../constants'; -import { get, create } from '../../user'; +import { get, create, createUserCore } from '../../user'; import { IConnectedUser, IUser, SignerType, walletType } from '../../types'; import { getAccountAddress } from './wallet'; -import { getDecryptedPrivateKey } from '.'; +import { IPGPHelper, PGPHelper, getDecryptedPrivateKey } from '.'; import { isValidCAIP10NFTAddress, isValidETHAddress, @@ -78,6 +78,15 @@ export const getConnectedUserV2 = async ( wallet: walletType, privateKey: string | null, env: ENV +): Promise<IConnectedUser> => { + return await getConnectedUserV2Core(wallet, privateKey, env, PGPHelper); +}; + +export const getConnectedUserV2Core = async ( + wallet: walletType, + privateKey: string | null, + env: ENV, + pgpHelper: IPGPHelper, ): Promise<IConnectedUser> => { const address = await getAccountAddress(wallet); const user = await get({ account: address, env: env || Constants.ENV.PROD }); @@ -111,7 +120,7 @@ export const getConnectedUserV2 = async ( createUserProps.signer = wallet.signer; } createUserProps.env = env; - const newUser = await create(createUserProps); + const newUser = await createUserCore(createUserProps, pgpHelper); const decryptedPrivateKey = await getDecryptedPrivateKey( wallet, newUser, diff --git a/packages/restapi/src/lib/chat/historicalMessages.ts b/packages/restapi/src/lib/chat/historicalMessages.ts index 18b42ace2..ae7f4377c 100644 --- a/packages/restapi/src/lib/chat/historicalMessages.ts +++ b/packages/restapi/src/lib/chat/historicalMessages.ts @@ -3,6 +3,8 @@ import { pCAIP10ToWallet } from '../helpers'; import { AccountEnvOptionsType, IMessageIPFS } from '../types'; import { get } from '../user'; import { + IPGPHelper, + PGPHelper, addDeprecatedInfoToMessages, decryptConversation, getMessagesService, @@ -27,8 +29,14 @@ export interface HistoricalMessagesOptionsType extends AccountEnvOptionsType { /** * Get all the messages exchanged between users after the threadhash. */ -export const history = async ( - options: HistoricalMessagesOptionsType + +export const history = async(options: HistoricalMessagesOptionsType) => { + return await historyCore(options, PGPHelper); +} + +export const historyCore = async ( + options: HistoricalMessagesOptionsType, + pgpHelper: IPGPHelper ): Promise<IMessageIPFS[]> => { const { threadhash, diff --git a/packages/restapi/src/lib/chat/latestMessage.ts b/packages/restapi/src/lib/chat/latestMessage.ts index 910427c49..0be7df08f 100644 --- a/packages/restapi/src/lib/chat/latestMessage.ts +++ b/packages/restapi/src/lib/chat/latestMessage.ts @@ -1,5 +1,6 @@ import Constants from '../constants'; import { AccountEnvOptionsType } from '../types'; +import { IPGPHelper, PGPHelper } from './helpers'; import { history } from './historicalMessages'; export interface LatestMessagesOptionsType extends AccountEnvOptionsType { @@ -11,7 +12,11 @@ export interface LatestMessagesOptionsType extends AccountEnvOptionsType { /** * Get the latest chat message */ + export const latest = async (options: LatestMessagesOptionsType) => { + return await latestCore(options, PGPHelper) +} +export const latestCore = async (options: LatestMessagesOptionsType, pgpHelper: IPGPHelper) => { const { threadhash, pgpPrivateKey = '', diff --git a/packages/restapi/src/lib/chat/send.ts b/packages/restapi/src/lib/chat/send.ts index 095f0fa73..674c85b52 100644 --- a/packages/restapi/src/lib/chat/send.ts +++ b/packages/restapi/src/lib/chat/send.ts @@ -3,13 +3,15 @@ import { getAPIBaseUrls, isValidETHAddress } from '../helpers'; import Constants, { MessageType, ENV } from '../constants'; import { ChatSendOptionsType, MessageWithCID, SignerType } from '../types'; import { + IPGPHelper, + PGPHelper, getAccountAddress, - getConnectedUserV2, + getConnectedUserV2Core, getUserDID, getWallet, } from './helpers'; import { conversationHash } from './conversationHash'; -import { ISendMessagePayload, sendMessagePayload } from './helpers'; +import { ISendMessagePayload, sendMessagePayloadCore } from './helpers'; import { getGroup } from './getGroup'; import { MessageObj } from '../types/messageTypes'; import { validateMessageObj } from '../validations/messageObject'; @@ -19,6 +21,13 @@ import { validateMessageObj } from '../validations/messageObject'; */ export const send = async ( options: ChatSendOptionsType +): Promise<MessageWithCID> => { + return await sendCore(options, PGPHelper); +}; + +export const sendCore = async ( + options: ChatSendOptionsType, + pgpHelper: IPGPHelper ): Promise<MessageWithCID> => { try { /** @@ -35,7 +44,7 @@ export const send = async ( await validateOptions(computedOptions); const wallet = getWallet({ account, signer }); - const sender = await getConnectedUserV2(wallet, pgpPrivateKey, env); + const sender = await getConnectedUserV2Core(wallet, pgpPrivateKey, env, pgpHelper); const receiver = await getUserDID(to, env); const API_BASE_URL = getAPIBaseUrls(env); const isGroup = isValidETHAddress(to) ? false : true; @@ -71,14 +80,15 @@ export const send = async ( apiEndpoint = `${API_BASE_URL}/v1/chat/message`; } - const body: ISendMessagePayload = await sendMessagePayload( + const body: ISendMessagePayload = await sendMessagePayloadCore( receiver, sender, messageObj, messageContent, messageType, group, - env + env, + pgpHelper ); return (await axios.post(apiEndpoint, body)).data; } catch (err) { diff --git a/packages/restapi/src/lib/chat/updateGroup.ts b/packages/restapi/src/lib/chat/updateGroup.ts index af5633be3..b8967095d 100644 --- a/packages/restapi/src/lib/chat/updateGroup.ts +++ b/packages/restapi/src/lib/chat/updateGroup.ts @@ -11,8 +11,11 @@ import { import { IUpdateGroupRequestPayload, updateGroupPayload, - sign, getWallet, + IPGPHelper, + PGPHelper, + getConnectedUserV2Core, + sign, getAccountAddress, getUserDID, getConnectedUserV2, @@ -43,8 +46,16 @@ export interface ChatUpdateGroupType extends EnvOptionsType { /** * Update Group information */ + export const updateGroup = async ( options: ChatUpdateGroupType +) => { + return await updateGroupCore(options, PGPHelper); +} + +export const updateGroupCore = async ( + options: ChatUpdateGroupType, + pgpHelper: IPGPHelper ): Promise<GroupDTO> => { const { chatId, @@ -78,8 +89,7 @@ export const updateGroup = async ( address, groupDescription ); - - const connectedUser = await getConnectedUserV2(wallet, pgpPrivateKey, env); + const connectedUser = await getConnectedUserV2Core(wallet, pgpPrivateKey, env, pgpHelper); const convertedMembersPromise = members.map(async (each) => { return getUserDID(each, env); }); @@ -97,7 +107,7 @@ export const updateGroup = async ( chatId: chatId, }; const hash = CryptoJS.SHA256(JSON.stringify(bodyToBeHashed)).toString(); - const signature: string = await sign({ + const signature: string = await pgpHelper.sign({ message: hash, signingKey: connectedUser.privateKey!, }); diff --git a/packages/restapi/src/lib/payloads/constants.ts b/packages/restapi/src/lib/payloads/constants.ts index da01fafc7..65d76c858 100644 --- a/packages/restapi/src/lib/payloads/constants.ts +++ b/packages/restapi/src/lib/payloads/constants.ts @@ -32,6 +32,7 @@ export const SOURCE_TYPES = { ARBITRUMONE_MAINNET: "ARBITRUMONE_MAINNET", THE_GRAPH: 'THE_GRAPH', PUSH_VIDEO: 'PUSH_VIDEO', + SIMULATE: 'SIMULATE' }; export enum IDENTITY_TYPE { diff --git a/packages/restapi/src/lib/payloads/sendNotifications.ts b/packages/restapi/src/lib/payloads/sendNotifications.ts index eb262f5f8..091ef1c84 100644 --- a/packages/restapi/src/lib/payloads/sendNotifications.ts +++ b/packages/restapi/src/lib/payloads/sendNotifications.ts @@ -17,9 +17,14 @@ import { isValidCAIP10NFTAddress, isValidETHAddress, } from '../helpers'; -import { IDENTITY_TYPE, DEFAULT_DOMAIN } from './constants'; +import { + IDENTITY_TYPE, + DEFAULT_DOMAIN, + NOTIFICATION_TYPE, + SOURCE_TYPES, +} from './constants'; import { ENV } from '../constants'; - +import { getChannel } from '../channels/getChannel'; /** * Validate options for some scenarios */ @@ -53,6 +58,35 @@ function validateOptions(options: any) { } } +/** + * + * @param payloadOptions channel, recipient and type tp verify whether it is a simulate type + * @returns boolean + */ +async function checkSimulateNotification(payloadOptions: { + channel: string; + recipient: string | string[] | undefined; + type: NOTIFICATION_TYPE; + env: ENV | undefined; +}): Promise<boolean> { + const { channel, recipient, type, env } = payloadOptions || {}; + // fetch channel info + const channelInfo = await getChannel({ + channel: channel, + env: env, + }); + // check if channel exists, if it does then its not simulate type + if (channelInfo) return false; + else { + // if no channel info found, check if channel address = recipient and notification type is targeted + const convertedRecipient = + typeof recipient == 'string' && recipient?.split(':').length == 3 + ? recipient.split(':')[2] + : recipient; + return channel == convertedRecipient && type == NOTIFICATION_TYPE.TARGETTED; + } +} + export async function sendNotification(options: ISendNotificationInputOptions) { try { const { @@ -133,7 +167,14 @@ export async function sendNotification(options: ISendNotificationInputOptions) { ipfsHash, }); - const source = getSource(chainId, identityType, senderType); + const source = (await checkSimulateNotification({ + channel: options.channel, + recipient: options.recipients, + type: options.type, + env: options.env, + })) + ? SOURCE_TYPES.SIMULATE + : getSource(chainId, identityType, senderType); const apiPayload = { verificationProof, diff --git a/packages/restapi/src/lib/pushNotification/PushNotificationTypes.ts b/packages/restapi/src/lib/pushNotification/PushNotificationTypes.ts index a010e3472..c67947978 100644 --- a/packages/restapi/src/lib/pushNotification/PushNotificationTypes.ts +++ b/packages/restapi/src/lib/pushNotification/PushNotificationTypes.ts @@ -54,10 +54,7 @@ export type IPayload = { body?: string; cta?: string; embed?: string; - index?: { - index: number; - value?: number; - }; + category?: number; meta?: { domain?: string; type: `${ADDITIONAL_META_TYPE}+${number}`; @@ -106,6 +103,8 @@ export type NotificationSetting = { data?: { upper: number; lower: number; + enabled?: boolean; + ticker?: number; }; }; diff --git a/packages/restapi/src/lib/pushNotification/channel.ts b/packages/restapi/src/lib/pushNotification/channel.ts index da57c04bb..0d7af56a1 100644 --- a/packages/restapi/src/lib/pushNotification/channel.ts +++ b/packages/restapi/src/lib/pushNotification/channel.ts @@ -110,12 +110,18 @@ export class Channel extends PushNotificationBaseClass { send = async (recipients: string[], options: NotificationOptions) => { try { this.checkSignerObjectExists(); + const info = await this.info(options.channel?? this.account); + let settings = null; + if(info && info.channel_settings){ + settings = JSON.parse(info.channel_settings); + } const lowLevelPayload = this.generateNotificationLowLevelPayload({ signer: this.signer!, env: this.env!, recipients: recipients, options: options, channel: options.channel ?? this.account, + settings: settings, }); return await PUSH_PAYLOAD.sendNotification(lowLevelPayload); } catch (error) { @@ -159,7 +165,7 @@ export class Channel extends PushNotificationBaseClass { config.MIN_TOKEN_BALANCE[this.env!].toString(), 18 ); - if (fees.gte(balance)) { + if (fees.gt(balance)) { throw new Error('Insufficient PUSH balance'); } // if alias is passed, check for the caip @@ -263,7 +269,7 @@ export class Channel extends PushNotificationBaseClass { 18 ); const totalFees = fees.mul(counter) - if (totalFees.gte(balance)) { + if (totalFees.gt(balance)) { throw new Error('Insufficient PUSH balance'); } // if alias is passed, check for the caip @@ -396,7 +402,7 @@ export class Channel extends PushNotificationBaseClass { config.MIN_TOKEN_BALANCE[this.env!].toString(), 18 ); - if (fees.gte(balance)) { + if (fees.gt(balance)) { throw new Error('Insufficient PUSH balance'); } const allowanceAmount = await this.fetchAllownace( diff --git a/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts b/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts index 37d6b138c..30a06c6c4 100644 --- a/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts +++ b/packages/restapi/src/lib/pushNotification/pushNotificationBase.ts @@ -30,6 +30,8 @@ const SETTING_DELIMITER = '-'; const SETTING_SEPARATOR = '+'; const SLIDER_TYPE = 2; const BOOLEAN_TYPE = 1; +const DEFAULT_ENABLE_VALUE = '1'; +const DEFAULT_TICKER_VALUE = '1'; export const FEED_MAP = { INBOX: false, @@ -133,12 +135,14 @@ export class PushNotificationBaseClass { recipients, options, channel, + settings, }: { signer: SignerType; env: ENV; recipients: string[]; options: NotificationOptions; channel?: string; + settings: any | null; }): ISendNotificationInputOptions { if (!channel) { channel = `${this.account}`; @@ -146,17 +150,18 @@ export class PushNotificationBaseClass { const notificationType = this.getNotificationType(recipients, channel); const identityType = IDENTITY_TYPE.DIRECT_PAYLOAD; // fetch the minimal version based on conifg that was passed - let index; - if (options.payload?.index) { - if (options.payload?.index.value) { + let index = ''; + if (options.payload?.category && settings) { + if (settings[options.payload.category - 1].type == 2) { index = - options.payload.index.index + + options.payload.category + SETTING_DELIMITER + SLIDER_TYPE + SETTING_DELIMITER + - options.payload.index.value; - } else { - index = options.payload.index.index + SETTING_DELIMITER + BOOLEAN_TYPE; + settings[options.payload.category - 1].default; + } + if (settings[options.payload.category - 1].type == 1) { + index = options.payload.category + SETTING_DELIMITER + BOOLEAN_TYPE; } } const notificationPayload: ISendNotificationInputOptions = { @@ -174,7 +179,7 @@ export class PushNotificationBaseClass { etime: options.config?.expiry, silent: options.config?.silent, additionalMeta: options.payload?.meta, - index: options.payload?.index ? index : '', + index: options.payload?.category ? index : '', }, recipients: notificationType.recipient, graph: options.advanced?.graph, @@ -656,7 +661,7 @@ export class PushNotificationBaseClass { return 0; } - protected getMinimalSetting(configuration: NotificationSettings): { + public getMinimalSetting(configuration: NotificationSettings): { setting: string; description: string; } { @@ -664,28 +669,37 @@ export class PushNotificationBaseClass { let notificationSettingDescription = ''; for (let i = 0; i < configuration.length; i++) { const ele = configuration[i]; - if (ele.type == 0) { + if (ele.type == BOOLEAN_TYPE) { notificationSetting = notificationSetting + SETTING_SEPARATOR + - ele.type + + BOOLEAN_TYPE + SETTING_DELIMITER + ele.default; notificationSettingDescription = notificationSettingDescription + SETTING_SEPARATOR + ele.description; } - if (ele.type == 1) { + if (ele.type == SLIDER_TYPE) { if (ele.data) { + const enabled = + ele.data && ele.data.enabled != undefined + ? Number(ele.data.enabled).toString() + : DEFAULT_ENABLE_VALUE; + const ticker = ele.data.ticker ?? DEFAULT_TICKER_VALUE; notificationSetting = notificationSetting + SETTING_SEPARATOR + - ele.type + + SLIDER_TYPE + + SETTING_DELIMITER + + enabled + SETTING_DELIMITER + ele.default + SETTING_DELIMITER + ele.data.lower + SETTING_DELIMITER + - ele.data.upper; + ele.data.upper + + SETTING_DELIMITER + + ticker; notificationSettingDescription = notificationSettingDescription + @@ -701,7 +715,7 @@ export class PushNotificationBaseClass { } protected getMinimalUserSetting(setting: UserSetting[]) { - if(!setting){ + if (!setting) { return null; } let userSetting = ''; diff --git a/packages/restapi/src/lib/pushapi/PushAPI.ts b/packages/restapi/src/lib/pushapi/PushAPI.ts index e79fd5dc9..429b3aac3 100644 --- a/packages/restapi/src/lib/pushapi/PushAPI.ts +++ b/packages/restapi/src/lib/pushapi/PushAPI.ts @@ -73,10 +73,7 @@ export class PushAPI { static async initialize( signer: SignerType, - options?: PushAPIInitializeProps, - version?: typeof Constants.ENC_TYPE_V1 | typeof Constants.ENC_TYPE_V3, - versionMeta?: { NFTPGP_V1?: { password: string } }, - autoUpgrade?: boolean + options?: PushAPIInitializeProps ): Promise<PushAPI> { try { // Default options @@ -97,10 +94,12 @@ export class PushAPI { const settings = { ...defaultOptions, ...options, - version: version || defaultOptions.version, - versionMeta: versionMeta || defaultOptions.versionMeta, + version: options?.version || defaultOptions.version, + versionMeta: options?.versionMeta || defaultOptions.versionMeta, autoUpgrade: - autoUpgrade !== undefined ? autoUpgrade : defaultOptions.autoUpgrade, + options?.autoUpgrade !== undefined + ? options?.autoUpgrade + : defaultOptions.autoUpgrade, streamOptions: { ...defaultOptions.streamOptions, ...(options?.streamOptions ?? {}), @@ -168,7 +167,10 @@ export class PushAPI { decryptedPGPPrivateKey, signer, settings.progressHook, - settings.streamOptions + { + ...settings.streamOptions, + env: settings.env, // Use the env from the top-level PushAPIInitializeProps + } ); if (streamInstance) { api.stream = streamInstance; diff --git a/packages/restapi/src/lib/user/createUser.ts b/packages/restapi/src/lib/user/createUser.ts index 2d812de3f..9e04da1e0 100644 --- a/packages/restapi/src/lib/user/createUser.ts +++ b/packages/restapi/src/lib/user/createUser.ts @@ -1,6 +1,7 @@ import { + IPGPHelper, + PGPHelper, createUserService, - generateKeyPair, generateRandomSecret, getAccountAddress, getWallet, @@ -41,9 +42,14 @@ export type CreateUserProps = { interface ICreateUser extends IUser { decryptedPrivateKey?: string; } -export const create = async ( - options: CreateUserProps -): Promise<ICreateUser> => { + + +export const create = async (options:CreateUserProps):Promise<ICreateUser>=>{ + return await createUserCore(options, PGPHelper) +} + +export const createUserCore = async ( options: CreateUserProps, + pgpHelper: IPGPHelper): Promise<ICreateUser> => { const passPrefix = '$0Pc'; //password prefix to ensure password validation const { env = Constants.ENV.PROD, @@ -87,7 +93,7 @@ export const create = async ( // Report Progress progressHook?.(PROGRESSHOOK['PUSH-CREATE-01'] as ProgressHookType); - const keyPairs = await generateKeyPair(); + const keyPairs = await pgpHelper.generateKeyPair(); // Report Progress progressHook?.(PROGRESSHOOK['PUSH-CREATE-02'] as ProgressHookType); diff --git a/packages/restapi/src/lib/user/getFeedsPerChannel.ts b/packages/restapi/src/lib/user/getFeedsPerChannel.ts index fb6d902d4..0ff7db014 100644 --- a/packages/restapi/src/lib/user/getFeedsPerChannel.ts +++ b/packages/restapi/src/lib/user/getFeedsPerChannel.ts @@ -35,7 +35,7 @@ export const getFeedsPerChannel = async (options: FeedsPerChannelOptionsType) => throw new Error('channels cannot be empty'); } const _channel = await getCAIPAddress(env, channels[0], 'Channel'); - const apiEndpoint = `${API_BASE_URL}/v1/users/${_channel}/channels/${_user}/feeds`; + const apiEndpoint = `${API_BASE_URL}/v1/users/${_user}/channels/${_channel}/feeds`; const queryObj = { page, limit: getLimit(limit), diff --git a/packages/restapi/src/lib/user/index.ts b/packages/restapi/src/lib/user/index.ts index d5c2b9084..3d5fff4f8 100644 --- a/packages/restapi/src/lib/user/index.ts +++ b/packages/restapi/src/lib/user/index.ts @@ -1,5 +1,6 @@ import { authUpdate } from './auth.updateUser'; -import { profileUpdate } from './profile.updateUser'; +import { profileUpdate, profileUpdateCore } from './profile.updateUser'; +export { ProfileUpdateProps } from './profile.updateUser'; export * from './createUser'; export * from './getFeeds'; export * from './getSubscriptions'; @@ -16,4 +17,5 @@ export const auth = { }; export const profile = { update: profileUpdate, + updateCore: profileUpdateCore, }; diff --git a/packages/restapi/src/lib/user/profile.updateUser.ts b/packages/restapi/src/lib/user/profile.updateUser.ts index 85b102f07..d62980d0e 100644 --- a/packages/restapi/src/lib/user/profile.updateUser.ts +++ b/packages/restapi/src/lib/user/profile.updateUser.ts @@ -1,6 +1,6 @@ import axios from 'axios'; import * as CryptoJS from 'crypto-js'; -import { getUserDID, sign } from '../chat/helpers'; +import { IPGPHelper, PGPHelper, getUserDID } from '../chat/helpers'; import Constants, { ENV } from '../constants'; import { getAPIBaseUrls, @@ -12,7 +12,7 @@ import { get } from './getUser'; import { populateDeprecatedUser } from '../utils/populateIUser'; import PROGRESSHOOK from '../progressHook'; -type ProfileUpdateProps = { +export type ProfileUpdateProps = { /** * PGP Private Key */ @@ -39,6 +39,13 @@ type ProfileUpdateProps = { */ export const profileUpdate = async ( options: ProfileUpdateProps +): Promise<IUser> => { + return profileUpdateCore(options, PGPHelper); +}; + +export const profileUpdateCore = async ( + options: ProfileUpdateProps, + pgpHelper: IPGPHelper ): Promise<IUser> => { const { pgpPrivateKey, @@ -85,7 +92,7 @@ export const profileUpdate = async ( blockedUsersList: profile.blockedUsersList ? blockedUsersList : [], }; const hash = CryptoJS.SHA256(JSON.stringify(updatedProfile)).toString(); - const signature = await sign({ + const signature = await pgpHelper.sign({ message: hash, signingKey: pgpPrivateKey, }); diff --git a/packages/restapi/tests/lib/chat/send.test.ts b/packages/restapi/tests/lib/chat/send.test.ts index 5aeb21512..88dba0595 100644 --- a/packages/restapi/tests/lib/chat/send.test.ts +++ b/packages/restapi/tests/lib/chat/send.test.ts @@ -19,7 +19,7 @@ import { CHAT } from '../../../src/lib/types/messageTypes'; chai.use(chaiAsPromised); const _env = Constants.ENV.DEV; -describe.only('PushAPI.chat.send', () => { +describe('PushAPI.chat.send', () => { const provider = ethers.getDefaultProvider(5); let _signer1: any; let walletAddress1: string; diff --git a/packages/restapi/tests/lib/pushNotification/channel.test.ts b/packages/restapi/tests/lib/pushNotification/channel.test.ts index 579fcb3c4..bfee0e945 100644 --- a/packages/restapi/tests/lib/pushNotification/channel.test.ts +++ b/packages/restapi/tests/lib/pushNotification/channel.test.ts @@ -14,6 +14,9 @@ describe('PushAPI.channel functionality', () => { let account1: string; let signer2: any; let account2: string; + let userNoChannel: PushAPI; + let noChannelSigner: any; + let noChannelAddress: string; beforeEach(async () => { signer1 = new ethers.Wallet(`0x${process.env['WALLET_PRIVATE_KEY']}`); @@ -29,6 +32,11 @@ describe('PushAPI.channel functionality', () => { provider ); account2 = await signer2.getAddress(); + + const WALLET = ethers.Wallet.createRandom(); + noChannelSigner = new ethers.Wallet(WALLET.privateKey); + noChannelAddress = await noChannelSigner.getAddress(); + enum ENV { PROD = 'prod', STAGING = 'staging', @@ -39,12 +47,14 @@ describe('PushAPI.channel functionality', () => { LOCAL = 'local', } // initialisation with signer and provider - userKate = await PushAPI.initialize(signer2) + userKate = await PushAPI.initialize(signer2, { env: ENV.DEV }); // initialisation with signer userAlice = await PushAPI.initialize(signer2); // TODO: remove signer1 after chat makes signer as optional //initialisation without signer userBob = await PushAPI.initialize(signer1); + // initialisation with a signer that has no channel + userNoChannel = await PushAPI.initialize(noChannelSigner); }); describe('channel :: info', () => { @@ -65,7 +75,7 @@ describe('PushAPI.channel functionality', () => { const res = await userBob.channel.info( 'eip155:5:0x93A829d16DE51745Db0530A0F8E8A9B8CA5370E5' ); - // console.log(res); + // console.log(res); expect(res).not.null; }); }); @@ -73,7 +83,7 @@ describe('PushAPI.channel functionality', () => { describe('channel :: search', () => { it('Without signer and account : Should return response', async () => { const res = await userBob.channel.search(' '); - // console.log(res); + // console.log(res); expect(res).not.null; }); @@ -207,6 +217,7 @@ describe('PushAPI.channel functionality', () => { body: 'testing with random body', cta: 'https://google.com/', embed: 'https://avatars.githubusercontent.com/u/64157541?s=200&v=4', + category: 2, }, } ); @@ -257,6 +268,41 @@ describe('PushAPI.channel functionality', () => { ); expect(res.status).to.equal(204); }); + + it('With signer : subset : Should send notification with title and body along with additional options for alias', async () => { + const res = await userAlice.channel.send( + [ + 'eip155:97:0xD8634C39BBFd4033c0d3289C4515275102423681', + 'eip155:97:0x93A829d16DE51745Db0530A0F8E8A9B8CA5370E5', + ], + { + notification: { + title: 'hi', + body: 'test-subset', + }, + payload: { + title: 'testing first subset notification', + body: 'testing with random body', + cta: 'https://google.com/', + embed: 'https://avatars.githubusercontent.com/u/64157541?s=200&v=4', + }, + channel: 'eip155:97:0xD8634C39BBFd4033c0d3289C4515275102423681', + } + ); + expect(res.status).to.equal(204); + }); + it('With signer : SIMULATED : Should send notification with title and body', async () => { + const res = await userNoChannel.channel.send( + [`eip155:5:${noChannelAddress}`], + { + notification: { + title: 'hi', + body: 'test-targeted-simulated', + }, + } + ); + expect(res.status).to.equal(204); + }); }); describe.skip('channel :: update', () => { @@ -285,11 +331,16 @@ describe('PushAPI.channel functionality', () => { }, 10000000000); }); - describe.skip('channel :: settings', () => { + describe('channel :: settings', () => { it('Should create channel', async () => { const res = await userKate.channel.setting([ - { type: 0, default: 1, description: 'My Notif Settings' }, - {type: 1, default: 5, description: "My notif setting 2", data: {upper:100, lower:5}} + { + type: 2, + default: 5, + description: 'My notif setting 2', + data: { upper: 100, lower: 5, ticker: 10, enabled: true }, + }, + { type: 1, default: 1, description: 'My Notif Settings' }, ]); // console.log(res) expect(res).not.null; diff --git a/packages/restapi/tests/lib/pushNotification/notification.test.ts b/packages/restapi/tests/lib/pushNotification/notification.test.ts index 85913a1c7..fe0ab8997 100644 --- a/packages/restapi/tests/lib/pushNotification/notification.test.ts +++ b/packages/restapi/tests/lib/pushNotification/notification.test.ts @@ -24,7 +24,7 @@ describe('PushAPI.notification functionality', () => { `0x${process.env['NFT_HOLDER_WALLET_PRIVATE_KEY_1']}` ); account1 = await signer1.getAddress(); - + const provider = new ethers.providers.JsonRpcProvider( 'https://goerli.blockpi.network/v1/rpc/public' ); @@ -138,7 +138,14 @@ describe('PushAPI.notification functionality', () => { it('With signer object: Should subscribe', async () => { const res = await userAlice.notification.subscribe( - 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681' + 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681', { + settings: [{ + enabled: false + },{ + enabled: false, + value: 0 + }, ] + } ); // console.log(res) expect(res).not.null; @@ -202,48 +209,6 @@ describe('PushAPI.notification functionality', () => { // await userAlice.uploadToIPFSViaPushNode("test") // }) - // it('Should get proper minnimal payload', () => { - // const inputData = [ - // { - // type: 0, - // default: 1, - // description: 'test1', - // }, - // { - // type: 1, - // default: 10, - // description: 'test2', - // data: { - // upper: 100, - // lower: 1, - // }, - // }, - // ]; - - // const minimalSettings = userAlice.getMinimalSetting(inputData); - // console.log(minimalSettings); - // }); - - // it('Should get proper minnimal payload', () => { - // const inputData = [ - // { - // type: 1, - // default: 10, - // description: 'test2', - // data: { - // upper: 100, - // lower: 1, - // }, - // }, - // { - // type: 0, - // default: 1, - // description: 'test1', - // }, - // ]; - - // const minimalSettings = userAlice.getMinimalSetting(inputData); - // console.log(minimalSettings); - // }); - // }); -}); + + }); +// }); diff --git a/packages/restapi/tests/lib/pushNotification/onchain.test.ts b/packages/restapi/tests/lib/pushNotification/onchain.test.ts index 647b20346..b26a7a2cc 100644 --- a/packages/restapi/tests/lib/pushNotification/onchain.test.ts +++ b/packages/restapi/tests/lib/pushNotification/onchain.test.ts @@ -95,6 +95,118 @@ // console.log(addDelegate); // }); + // it.only('test with ethers', async () => { + // const account2 = await signer2.getAddress(); + // const userEthers = new PushNotificationBaseClass(signer2, ENV.STAGING, account2,); + // const contract = userEthers.createContractInstance("0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C", config.ABIS.CORE, goerli) + // const res = await userEthers.fetchUpdateCounter(contract, account2); + // console.log(res) + // const ethersContract = await userEthers.createContractInstance( + // '0x2b9bE9259a4F5Ba6344c1b1c07911539642a2D33', + // abi, + // goerli + // ); + // const balance2 = await userEthers.fetchBalance( + // ethersContract, + // '0xD8634C39BBFd4033c0d3289C4515275102423681' + // ); + // console.log(balance2); + // const allowance2 = await userEthers.fetchAllownace( + // ethersContract, + // '0xD8634C39BBFd4033c0d3289C4515275102423681', + // '0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C' + // ); + // console.log(allowance2); + // const approveAmount2 = ethers.BigNumber.from(10000); + // const approveRes2 = await userEthers.approveToken( + // ethersContract, + // '0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C', + // approveAmount2 + // ); + // console.log(approveRes2); + // }); + // it.only('Should get proper minnimal payload', async() => { + // const inputData = [ + // { + // type: 1, + // default: 1, + // description: 'test1', + // }, + // { + // type: 2, + // default: 10, + // description: 'test2', + // data: { + // upper: 100, + // lower: 1, + // }, + // }, + // ]; + // const account2 = await signer2.getAddress(); + // const userAlice = new PushNotificationBaseClass(signer2, ENV.STAGING, account2,); + // const minimalSettings = userAlice.getMinimalSetting(inputData); + // console.log(minimalSettings); + // }); + +// it.only('Should get proper minnimal payload', async() => { +// const inputData = [ +// { +// type: 1, +// default: 10, +// description: 'test2', +// data: { +// upper: 100, +// lower: 1, +// enabled: false +// }, +// }, +// { +// type: 0, +// default: 1, +// description: 'test1', +// }, +// ]; +// const account2 = await signer2.getAddress(); +// const userAlice = new PushNotificationBaseClass(signer2, ENV.STAGING, account2,); +// const minimalSettings = userAlice.getMinimalSetting(inputData); +// console.log(minimalSettings); +// }); + // it('testing with viem', async () => { + // const account2 = await signer2.getAddress(); + // const viemUser = new PushNotificationBaseClass(signer, ENV.STAGING, account2) + // const contract = viemUser.createContractInstance("0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C", config.ABIS.CORE, goerli) + // const res = await viemUser.fetchUpdateCounter(contract, account2); + // console.log(res) + // const viemContract = await userViem.createContractInstance( + // '0x2b9bE9259a4F5Ba6344c1b1c07911539642a2D33', + // abi, + // goerli + // ); + // const balance = await userViem.fetchBalance( + // viemContract, + // '0xD8634C39BBFd4033c0d3289C4515275102423681' + // ); + // console.log(balance); + // const allowance = await userViem.fetchAllownace( + // viemContract, + // '0xD8634C39BBFd4033c0d3289C4515275102423681', + // '0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C' + // ); + // console.log(allowance); + // const approveAmount = ethers.BigNumber.from(10000); + // const approveRes = await userViem.approveToken( + // viemContract, + // '0xd4E3ceC407cD36d9e3767cD189ccCaFBF549202C', + // approveAmount + // ); + // console.log(approveRes); + + // const addDelegate = await userViem.delegate.add( + // 'eip155:5:0xD8634C39BBFd4033c0d3289C4515275102423681' + // ); + // console.log(addDelegate); + // }); + // it.only('test with ethers', async () => { // const account2 = await signer2.getAddress(); // const userEthers = new PushNotificationBaseClass(signer2, ENV.STAGING, account2,); diff --git a/packages/uiweb/package.json b/packages/uiweb/package.json index f369a06ba..fbd33cd9a 100644 --- a/packages/uiweb/package.json +++ b/packages/uiweb/package.json @@ -19,7 +19,7 @@ "date-fns": "^2.28.0", "emoji-picker-react": "^4.4.9", "ethers": "^5.6.8", - "font-awesome": "^4.7.0", + "gif-picker-react": "^1.1.0", "html-react-parser": "^1.4.13", "livekit-client": "^1.13.3", diff --git a/packages/uiweb/src/lib/components/chat/ChatProfile/ChatProfile.tsx b/packages/uiweb/src/lib/components/chat/ChatProfile/ChatProfile.tsx index 4cb80bc97..e47d24135 100644 --- a/packages/uiweb/src/lib/components/chat/ChatProfile/ChatProfile.tsx +++ b/packages/uiweb/src/lib/components/chat/ChatProfile/ChatProfile.tsx @@ -22,11 +22,9 @@ import { IGroup } from '../../../types'; import { isValidETHAddress } from '../helpers/helper'; import { IChatProfile, - IChatTheme, MODAL_BACKGROUND_TYPE, MODAL_POSITION_TYPE, - ModalBackgroundType, - ModalPositionType, + } from '../exportedTypes'; import { InfuraAPIKey, allowedNetworks, device } from '../../../config'; import { resolveNewEns, shortenText } from '../../../helpers'; @@ -37,77 +35,6 @@ import InfoIcon from '../../../icons/infodark.svg'; import VerticalEllipsisIcon from '../../../icons/VerticalEllipsis.svg'; import { TokenGatedSvg } from '../../../icons/TokenGatedSvg'; -type OptionProps = { - options: boolean; - setOptions: React.Dispatch<React.SetStateAction<boolean>>; - isGroup: boolean; - groupInfo: IGroup | null | undefined; - setGroupInfo: React.Dispatch<React.SetStateAction<IGroup | null | undefined>>; - theme: IChatTheme; - groupInfoModalBackground: ModalBackgroundType; -}; - -const Options = ({ - options, - setOptions, - isGroup, - groupInfo, - setGroupInfo, - groupInfoModalBackground, - theme, -}: OptionProps) => { - const DropdownRef = useRef(null); - const [modal, setModal] = useState(false); - - useClickAway(DropdownRef, () => { - setOptions(false); - }); - - const ShowModal = () => { - setModal(true); - }; - - if (groupInfo && isGroup) { - return ( - <ImageItem onClick={() => setOptions(true)}> - <Image - src={VerticalEllipsisIcon} - height="21px" - maxHeight="32px" - width={'auto'} - cursor="pointer" - /> - - {options && ( - <DropDownBar theme={theme} ref={DropdownRef}> - <DropDownItem cursor="pointer" onClick={ShowModal}> - <Image - src={InfoIcon} - height="21px" - maxHeight="21px" - width={'auto'} - cursor="pointer" - /> - - <TextItem cursor="pointer">Group Info</TextItem> - </DropDownItem> - </DropDownBar> - )} - {modal && ( - <GroupInfoModal - theme={theme} - setModal={setModal} - groupInfo={groupInfo} - setGroupInfo={setGroupInfo} - groupInfoModalBackground={groupInfoModalBackground} - /> - )} - </ImageItem> - ); - } else { - return null; - } -}; export const ChatProfile: React.FC<IChatProfile> = ({ chatId, @@ -239,15 +166,7 @@ export const ChatProfile: React.FC<IChatProfile> = ({ </ImageItem> )} - {/* <Options - options={options} - setOptions={setOptions} - isGroup={isGroup} - groupInfo={groupInfo} - setGroupInfo={setGroupInfo} - theme={theme} - groupInfoModalBackground={groupInfoModalBackground} - /> */} + </Section> {modal && ( <GroupInfoModal diff --git a/packages/uiweb/src/lib/components/chat/ConnectButton/ConnectButton.tsx b/packages/uiweb/src/lib/components/chat/ConnectButton/ConnectButton.tsx index 05e415351..45aa9c3ba 100644 --- a/packages/uiweb/src/lib/components/chat/ConnectButton/ConnectButton.tsx +++ b/packages/uiweb/src/lib/components/chat/ConnectButton/ConnectButton.tsx @@ -1,13 +1,11 @@ import { useContext, useEffect, useState } from 'react'; import styled from 'styled-components'; -import { Signer, ethers } from 'ethers'; +import { ethers } from 'ethers'; import { useAccount, useChatData } from '../../../hooks'; import { ThemeContext } from '../theme/ThemeProvider'; -import useGetChatProfile from '../../../hooks/useGetChatProfile'; -import useCreateChatProfile from '../../../hooks/useCreateChatProfile'; -import useDecryptPGPKey from '../../../hooks/useDecryptPGPKey'; + import { getAddressFromSigner } from '../../../helpers'; import { IChatTheme } from '../theme'; @@ -20,19 +18,13 @@ import { device } from '../../../config'; interface IThemeProps { theme?: IChatTheme; } -interface IConnectButtonProps { - autoConnect?: boolean; -} + export const ConnectButtonSub = ({autoConnect = false}) => { const {wallet, connecting , connect, disconnect} = useAccount(); const { signer, - pgpPrivateKey, - account, - env, - setPgpPrivateKey, setAccount, setSigner, } = useChatData(); @@ -59,7 +51,6 @@ export const ConnectButtonSub = ({autoConnect = false}) => { setUserData() }, [wallet]) - return !signer ? ( <ConnectButtonDiv theme={theme}> <button onClick={() => (wallet ? disconnect(wallet) : connect())}>{connecting ? 'connecting' : wallet ? 'disconnect' : 'Connect Wallet'}</button> diff --git a/packages/uiweb/src/lib/components/chat/CreateGroup/AddCriteria.tsx b/packages/uiweb/src/lib/components/chat/CreateGroup/AddCriteria.tsx index 354e0dfce..a1b846f3e 100644 --- a/packages/uiweb/src/lib/components/chat/CreateGroup/AddCriteria.tsx +++ b/packages/uiweb/src/lib/components/chat/CreateGroup/AddCriteria.tsx @@ -40,7 +40,6 @@ import { import useToast from '../reusables/NewToast'; import { CriteriaValidationErrorType, - Data, GuildData, PushData, Rule, diff --git a/packages/uiweb/src/lib/components/chat/CreateGroup/DefineCondition.tsx b/packages/uiweb/src/lib/components/chat/CreateGroup/DefineCondition.tsx index 58d3a5d44..9e3315279 100644 --- a/packages/uiweb/src/lib/components/chat/CreateGroup/DefineCondition.tsx +++ b/packages/uiweb/src/lib/components/chat/CreateGroup/DefineCondition.tsx @@ -23,7 +23,6 @@ export const DefineCondtion = ({ criteriaStateManager, }: ModalHeaderProps) => { const theme = useContext(ThemeContext); - const isMobile = useMediaQuery(device.mobileL); const criteriaState = criteriaStateManager.getSelectedCriteria(); diff --git a/packages/uiweb/src/lib/components/chat/MessageInput/MessageInput.tsx b/packages/uiweb/src/lib/components/chat/MessageInput/MessageInput.tsx index 7cde4ab9d..7a38fed61 100644 --- a/packages/uiweb/src/lib/components/chat/MessageInput/MessageInput.tsx +++ b/packages/uiweb/src/lib/components/chat/MessageInput/MessageInput.tsx @@ -228,13 +228,16 @@ export const MessageInput: React.FC<MessageInputProps> = ({ }, [chatId, pgpPrivateKey, account, env]); useEffect(() => { + console.log('in useEffect') + console.log(chatFeed) if (!account && !env && !chatId) return; if (account && env && chatId && chatFeed && chatFeed?.groupInformation) { setIsMember(checkIfMember(chatFeed, account)); setIsRules(checkIfAccessVerifiedGroup(chatFeed)); } }, [chatId, chatFeed, account, env]); - +console.log(isMember) +console.log(checkIfMember(chatFeed, account!)) const addEmoji = (emojiData: EmojiClickData, event: MouseEvent): void => { setTypedMessage(typedMessage + emojiData.emoji); setShowEmojis(false); @@ -370,9 +373,11 @@ export const MessageInput: React.FC<MessageInputProps> = ({ }; const updateChatFeed = async () => { + const chat = await fetchChat({ chatId }); if (Object.keys(chat || {}).length) { + setChatFeed(chat as IFeeds); } }; diff --git a/packages/uiweb/src/lib/components/chat/constants/index.ts b/packages/uiweb/src/lib/components/chat/constants/index.ts index 085844f58..c2ab37953 100644 --- a/packages/uiweb/src/lib/components/chat/constants/index.ts +++ b/packages/uiweb/src/lib/components/chat/constants/index.ts @@ -55,4 +55,4 @@ export const ACCESS_TYPE_TITLE = { }, }; -export * from './chainDetails'; \ No newline at end of file +export * from './chainDetails'; diff --git a/packages/uiweb/src/lib/components/chat/helpers/index.ts b/packages/uiweb/src/lib/components/chat/helpers/index.ts index 38c220c59..ab6b2d902 100644 --- a/packages/uiweb/src/lib/components/chat/helpers/index.ts +++ b/packages/uiweb/src/lib/components/chat/helpers/index.ts @@ -3,4 +3,4 @@ export * from './group'; export * from './helper'; export * from './tokenGatedGroup'; -export * from './addCriteriaUtilities'; \ No newline at end of file +export * from './addCriteriaUtilities'; diff --git a/packages/uiweb/src/lib/components/chat/reusables/DropDown.tsx b/packages/uiweb/src/lib/components/chat/reusables/DropDown.tsx index 17c8ce08e..b2ad919d8 100644 --- a/packages/uiweb/src/lib/components/chat/reusables/DropDown.tsx +++ b/packages/uiweb/src/lib/components/chat/reusables/DropDown.tsx @@ -56,6 +56,7 @@ function Dropdown({ document.body.removeChild(el); } }; + console.log(dropdownValues) return ( <> {dropdownValues.map((dropdownValue) => @@ -195,6 +196,7 @@ const DropdownItemContainer = styled(Section) <{ hoverBGColor?: string }>` flex-wrap: nowrap; white-space: nowrap; margin: 1px 0; +// width:100%; padding: 2px 8px; border-radius: 12px; cursor: pointer; diff --git a/packages/uiweb/src/lib/components/chat/reusables/NewToast.tsx b/packages/uiweb/src/lib/components/chat/reusables/NewToast.tsx index d154fc228..5556dbbec 100644 --- a/packages/uiweb/src/lib/components/chat/reusables/NewToast.tsx +++ b/packages/uiweb/src/lib/components/chat/reusables/NewToast.tsx @@ -72,7 +72,6 @@ const useToast = ( const showLoaderToast: ShowLoaderToastType = ({ loaderMessage }) => { isLoaderToastShown = true; - return (toastId.current = toast( <ThemeProvider theme={theme}> <LoaderToast diff --git a/packages/uiweb/src/lib/components/chat/reusables/index.ts b/packages/uiweb/src/lib/components/chat/reusables/index.ts index 6b3c23a54..0e48c3cc1 100644 --- a/packages/uiweb/src/lib/components/chat/reusables/index.ts +++ b/packages/uiweb/src/lib/components/chat/reusables/index.ts @@ -12,4 +12,4 @@ export * from './Button'; export * from './QuantityInput'; export * from './OptionButtons'; export * from './Checkbox'; -export * from './InfoContainer'; \ No newline at end of file +export * from './InfoContainer'; diff --git a/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotificationWidget.tsx b/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotificationWidget.tsx index 4d7ace1be..aecce02a6 100644 --- a/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotificationWidget.tsx +++ b/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotificationWidget.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { ChatAndNotificationMainContextProvider, ChatAndNotificationPropsContext, NotificationMainStateContextProvider } from '../../context'; -import 'font-awesome/css/font-awesome.min.css'; +// import 'font-awesome/css/font-awesome.min.css'; import { Constants } from '../../config'; import { ChatMainStateContextProvider } from '../../context'; diff --git a/packages/uiweb/src/lib/hooks/index.ts b/packages/uiweb/src/lib/hooks/index.ts index 7e06fc6dd..99ac2b8f2 100644 --- a/packages/uiweb/src/lib/hooks/index.ts +++ b/packages/uiweb/src/lib/hooks/index.ts @@ -11,4 +11,4 @@ export * from './useGetChatProfile'; export * from './useMediaQuery'; export * from './useCreateChatProfile'; export * from './useDecryptPGPKey'; -export * from './useTokenSymbolLoader'; \ No newline at end of file +export * from './useTokenSymbolLoader'; diff --git a/packages/uiweb/src/lib/icons/TokenGatedIcon.svg b/packages/uiweb/src/lib/icons/TokenGatedIcon.svg new file mode 100644 index 000000000..19c599954 --- /dev/null +++ b/packages/uiweb/src/lib/icons/TokenGatedIcon.svg @@ -0,0 +1,3 @@ +<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.75 0.25C7.82164 0.25 5.93657 0.821828 4.33319 1.89317C2.72982 2.96452 1.48013 4.48726 0.742179 6.26884C0.00422448 8.05042 -0.188858 10.0108 0.187348 11.9021C0.563554 13.7934 1.49215 15.5307 2.85571 16.8943C4.21927 18.2579 5.95656 19.1865 7.84787 19.5627C9.73919 19.9389 11.6996 19.7458 13.4812 19.0078C15.2627 18.2699 16.7855 17.0202 17.8568 15.4168C18.9282 13.8134 19.5 11.9284 19.5 10C19.4973 7.41498 18.4692 4.93661 16.6413 3.10872C14.8134 1.28084 12.335 0.25273 9.75 0.25ZM15.7613 12.7319C15.9318 12.8343 16.0547 13.0003 16.1029 13.1934C16.1511 13.3864 16.1206 13.5907 16.0181 13.7612C15.9157 13.9318 15.7497 14.0547 15.5566 14.1029C15.3636 14.1511 15.1593 14.1206 14.9888 14.0181L10.5 11.3247V16.1875C10.5 16.3864 10.421 16.5772 10.2803 16.7178C10.1397 16.8585 9.94892 16.9375 9.75 16.9375C9.55109 16.9375 9.36033 16.8585 9.21967 16.7178C9.07902 16.5772 9 16.3864 9 16.1875V11.3247L4.51125 14.0181C4.34069 14.1206 4.13641 14.1511 3.94337 14.1029C3.75032 14.0547 3.58432 13.9318 3.48188 13.7612C3.37944 13.5907 3.34895 13.3864 3.39713 13.1934C3.4453 13.0003 3.56819 12.8343 3.73875 12.7319L8.29219 10L3.73875 7.26813C3.56819 7.16569 3.4453 6.99968 3.39713 6.80664C3.34895 6.61359 3.37944 6.40932 3.48188 6.23875C3.58432 6.06818 3.75032 5.9453 3.94337 5.89712C4.13641 5.84895 4.34069 5.87944 4.51125 5.98187L9 8.67531V3.8125C9 3.61359 9.07902 3.42282 9.21967 3.28217C9.36033 3.14152 9.55109 3.0625 9.75 3.0625C9.94892 3.0625 10.1397 3.14152 10.2803 3.28217C10.421 3.42282 10.5 3.61359 10.5 3.8125V8.67531L14.9888 5.98187C15.0732 5.93115 15.1668 5.89756 15.2643 5.88302C15.3617 5.86848 15.4611 5.87327 15.5566 5.89712C15.6522 5.92098 15.7422 5.96342 15.8214 6.02204C15.9005 6.08065 15.9674 6.15429 16.0181 6.23875C16.0689 6.32321 16.1024 6.41683 16.117 6.51427C16.1315 6.6117 16.1267 6.71105 16.1029 6.80664C16.079 6.90222 16.0366 6.99218 15.978 7.07136C15.9193 7.15054 15.8457 7.2174 15.7613 7.26813L11.2078 10L15.7613 12.7319Z" fill="#657795"/> +</svg> diff --git a/packages/uiweb/yarn.lock b/packages/uiweb/yarn.lock index 1243a9ee0..d714d5fff 100644 --- a/packages/uiweb/yarn.lock +++ b/packages/uiweb/yarn.lock @@ -9,11 +9,6 @@ dependencies: regenerator-runtime "^0.13.11" -"@bufbuild/protobuf@^1.3.0": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-1.3.1.tgz#c4de66bacbe7ac97fe054e68314aeba6f45177f9" - integrity sha512-BUyJWutgP2S8K/1NphOJokuwDckXS4qI2T1pGZAlkFdZchWae3jm6fCdkcGbLlM1QLOcNFFePd+7Feo4BYGrJQ== - "@babel/runtime@^7.17.2", "@babel/runtime@^7.22.6": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8" @@ -21,6 +16,11 @@ dependencies: regenerator-runtime "^0.14.0" +"@bufbuild/protobuf@^1.3.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-1.3.1.tgz#c4de66bacbe7ac97fe054e68314aeba6f45177f9" + integrity sha512-BUyJWutgP2S8K/1NphOJokuwDckXS4qI2T1pGZAlkFdZchWae3jm6fCdkcGbLlM1QLOcNFFePd+7Feo4BYGrJQ== + "@coinbase/wallet-sdk@^3.7.1": version "3.7.2" resolved "https://registry.yarnpkg.com/@coinbase/wallet-sdk/-/wallet-sdk-3.7.2.tgz#7a89bd9e3a06a1f26d4480d8642af33fb0c7e3aa" @@ -933,32 +933,6 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.4.tgz#19654d1026cc410975d46445180e70a5089b3e7d" integrity sha512-qprfWkn82Iw821mcKofJ5Pk9wgioHicxcQMxx+5zt5GSKoqdWvgG5AxVmpmUUjzTLPVSH5auBrhI93Deayn/DA== -"@livekit/components-core@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@livekit/components-core/-/components-core-0.7.0.tgz#1283a34753c8f1bb805b987684a3e29d1bc2eb39" - integrity sha512-KwzqnW8V9G+4fXc4gOxpXqQFLpL/kFBn82sYO10zHjHfNKSw4pRj1sDLTWc5UF22W2Z461/bqMtB+3WGB/3Dtg== - dependencies: - "@floating-ui/dom" "^1.1.0" - email-regex "^5.0.0" - global-tld-list "^0.0.1139" - loglevel "^1.8.1" - rxjs "^7.8.0" - -"@livekit/components-react@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@livekit/components-react/-/components-react-1.2.2.tgz#202083f70d5fb5512077fd145e81232116601e0a" - integrity sha512-0ds0A/XUUG9zarAZdlUdOEJsKKVp7kwFS+wFBXgJ2KcQwNJVCZh+NY780QP4r9E8R+knRJy/kkmEGYcCxvrgWA== - dependencies: - "@livekit/components-core" "0.7.0" - "@react-hook/latest" "^1.0.3" - clsx "^2.0.0" - usehooks-ts "^2.9.1" - -"@livekit/components-styles@^1.0.6": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@livekit/components-styles/-/components-styles-1.0.6.tgz#2649c61a631efff37eb2326e100e34a84e597d71" - integrity sha512-/toY2NFJCU0NdeP9AB+CWW9kPf8gdpndIoR0hYTKjDb8pHPdXDu5NE7XyO8qKIeV4biRFGsQ9+C3giPNgYm9TA== - "@formatjs/ecma402-abstract@1.11.4": version "1.11.4" resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz#b962dfc4ae84361f9f08fbce411b4e4340930eda" @@ -1022,6 +996,32 @@ dependencies: "@lit-labs/ssr-dom-shim" "^1.0.0" +"@livekit/components-core@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@livekit/components-core/-/components-core-0.7.0.tgz#1283a34753c8f1bb805b987684a3e29d1bc2eb39" + integrity sha512-KwzqnW8V9G+4fXc4gOxpXqQFLpL/kFBn82sYO10zHjHfNKSw4pRj1sDLTWc5UF22W2Z461/bqMtB+3WGB/3Dtg== + dependencies: + "@floating-ui/dom" "^1.1.0" + email-regex "^5.0.0" + global-tld-list "^0.0.1139" + loglevel "^1.8.1" + rxjs "^7.8.0" + +"@livekit/components-react@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@livekit/components-react/-/components-react-1.2.2.tgz#202083f70d5fb5512077fd145e81232116601e0a" + integrity sha512-0ds0A/XUUG9zarAZdlUdOEJsKKVp7kwFS+wFBXgJ2KcQwNJVCZh+NY780QP4r9E8R+knRJy/kkmEGYcCxvrgWA== + dependencies: + "@livekit/components-core" "0.7.0" + "@react-hook/latest" "^1.0.3" + clsx "^2.0.0" + usehooks-ts "^2.9.1" + +"@livekit/components-styles@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@livekit/components-styles/-/components-styles-1.0.6.tgz#2649c61a631efff37eb2326e100e34a84e597d71" + integrity sha512-/toY2NFJCU0NdeP9AB+CWW9kPf8gdpndIoR0hYTKjDb8pHPdXDu5NE7XyO8qKIeV4biRFGsQ9+C3giPNgYm9TA== + "@livepeer/core-react@^1.8.0": version "1.8.0" resolved "https://registry.npmjs.org/@livepeer/core-react/-/core-react-1.8.0.tgz" @@ -3027,16 +3027,6 @@ find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -font-awesome@^4.7.0: - version "4.7.0" - resolved "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz" - integrity sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg== - for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -3325,19 +3315,6 @@ js-sha3@0.8.0: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -livekit-client@^1.13.3: - version "1.13.4" - resolved "https://registry.yarnpkg.com/livekit-client/-/livekit-client-1.13.4.tgz#af20a338334d6c9e3c81e7c9641222d95a532b75" - integrity sha512-7Ef80q7aWkgkFWfWBd+gv2AcUrubpt+oXYk+tXSWVkTXoPpm6xqrMPu3TNYKIzXQWt8IEbyPQLLVsCZpR7RBTg== - dependencies: - "@bufbuild/protobuf" "^1.3.0" - events "^3.3.0" - loglevel "^1.8.0" - sdp-transform "^2.14.1" - ts-debounce "^4.0.0" - typed-emitter "^2.1.0" - webrtc-adapter "^8.1.1" - json-rpc-engine@6.1.0, json-rpc-engine@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393" @@ -3400,6 +3377,19 @@ lit@2.7.6: lit-element "^3.3.0" lit-html "^2.7.0" +livekit-client@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/livekit-client/-/livekit-client-1.13.4.tgz#af20a338334d6c9e3c81e7c9641222d95a532b75" + integrity sha512-7Ef80q7aWkgkFWfWBd+gv2AcUrubpt+oXYk+tXSWVkTXoPpm6xqrMPu3TNYKIzXQWt8IEbyPQLLVsCZpR7RBTg== + dependencies: + "@bufbuild/protobuf" "^1.3.0" + events "^3.3.0" + loglevel "^1.8.0" + sdp-transform "^2.14.1" + ts-debounce "^4.0.0" + typed-emitter "^2.1.0" + webrtc-adapter "^8.1.1" + livepeer@2.8.0: version "2.8.0" resolved "https://registry.npmjs.org/livepeer/-/livepeer-2.8.0.tgz" @@ -3499,16 +3489,16 @@ lodash.uniqby@4.5.0: lodash._baseiteratee "~4.7.0" lodash._baseuniq "~4.6.0" -loglevel@^1.8.0, loglevel@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4" - integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg== - lodash.uniqby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww== +loglevel@^1.8.0, loglevel@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4" + integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg== + loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" @@ -3976,6 +3966,11 @@ scriptjs@^2.5.9: resolved "https://registry.npmjs.org/scriptjs/-/scriptjs-2.5.9.tgz" integrity sha512-qGVDoreyYiP1pkQnbnFAUIS5AjenNwwQBdl7zeos9etl+hYKWahjRTfzAZZYBv5xNHx7vNKCmaLDQZ6Fr2AEXg== +scrypt-js@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + sdp-transform@^2.14.1: version "2.14.1" resolved "https://registry.yarnpkg.com/sdp-transform/-/sdp-transform-2.14.1.tgz#2bb443583d478dee217df4caa284c46b870d5827" @@ -3986,11 +3981,6 @@ sdp@^3.2.0: resolved "https://registry.yarnpkg.com/sdp/-/sdp-3.2.0.tgz#8961420552b36663b4d13ddba6f478d1461896a5" integrity sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw== -scrypt-js@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" - integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== - semver@^7.3.8: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" @@ -4247,13 +4237,6 @@ tus-js-client@^3.1.0: proper-lockfile "^4.1.2" url-parse "^1.5.7" -typed-emitter@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/typed-emitter/-/typed-emitter-2.1.0.tgz#ca78e3d8ef1476f228f548d62e04e3d4d3fd77fb" - integrity sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA== - optionalDependencies: - rxjs "^7.5.2" - type@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" @@ -4264,6 +4247,13 @@ type@^2.7.2: resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== +typed-emitter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/typed-emitter/-/typed-emitter-2.1.0.tgz#ca78e3d8ef1476f228f548d62e04e3d4d3fd77fb" + integrity sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA== + optionalDependencies: + rxjs "^7.5.2" + typedarray-to-buffer@3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -4316,11 +4306,6 @@ usehooks-ts@^2.9.1: resolved "https://registry.yarnpkg.com/usehooks-ts/-/usehooks-ts-2.9.1.tgz#953d3284851ffd097432379e271ce046a8180b37" integrity sha512-2FAuSIGHlY+apM9FVlj8/oNhd+1y+Uwv5QNkMQz1oSfdHk4PXo1qoCw9I5M7j0vpH8CSWFJwXbVPeYDjLCx9PA== -uuid@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" - integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== - utf-8-validate@^5.0.2: version "5.0.10" resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" @@ -4349,6 +4334,11 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + valtio@1.11.0: version "1.11.0" resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.11.0.tgz#c029dcd17a0f99d2fbec933721fe64cfd32a31ed" diff --git a/workspace.json b/workspace.json index 163b6ba91..8f790ddab 100644 --- a/workspace.json +++ b/workspace.json @@ -5,7 +5,6 @@ "demonative": "apps/demonative", "examples-sdk-frontend-react": "packages/examples/sdk-frontend-react", "ledgerlive": "packages/ledgerlive", - "reactnative": "packages/reactnative", "restapi": "packages/restapi", "socket": "packages/socket", "uiembed": "packages/uiembed",