diff --git a/.gitignore b/.gitignore index 6d81c53530..718b680220 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ storybook-static envs/qwerty.env Cargo.lock nym-connect/Cargo.lock +.parcel-cache diff --git a/sdk/typescript/examples/parcel/README.md b/sdk/typescript/examples/parcel/README.md new file mode 100644 index 0000000000..371796c4e1 --- /dev/null +++ b/sdk/typescript/examples/parcel/README.md @@ -0,0 +1,13 @@ +# HTML Nym Mixnet Chat App bundled with Parcel + +This is an example of using the Nym Mixnet to send text chat messages in an app bundled with Parcel 2.0. + +You can use this example as a seed for a new project. + +Try out the chat app by running: + +``` +yarn +yarn start +``` + diff --git a/sdk/typescript/examples/parcel/package.json b/sdk/typescript/examples/parcel/package.json new file mode 100644 index 0000000000..f73af987c7 --- /dev/null +++ b/sdk/typescript/examples/parcel/package.json @@ -0,0 +1,52 @@ +{ + "name": "@nymproject/sdk-example-plain-html-parcel", + "description": "An example project that uses WASM and plain HTML bundled with Parcel v2", + "version": "1.0.0", + "license": "Apache-2.0", + "source": "src/index.html", + "browserslist": "> 0.5%, last 2 versions, not dead", + "dependencies": { + "@nymproject/sdk": "1" + }, + "devDependencies": { + "@nymproject/eslint-config-react-typescript": "^1.0.0", + "@types/jest": "^27.0.1", + "@types/node": "^16.7.13", + "@typescript-eslint/eslint-plugin": "^5.13.0", + "@typescript-eslint/parser": "^5.13.0", + "eslint": "^8.10.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-typescript": "^16.1.0", + "eslint-config-prettier": "^8.5.0", + "eslint-import-resolver-root-import": "^1.0.4", + "eslint-plugin-import": "^2.25.4", + "eslint-plugin-jest": "^26.1.1", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-prettier": "^4.0.0", + "jest": "^27.1.0", + "mini-css-extract-plugin": "^2.2.2", + "npm-run-all": "^4.1.5", + "prettier": "^2.5.1", + "ts-jest": "^27.0.5", + "typescript": "^4.6.2" + }, + "scripts": { + "prestart": "yarn build:dependencies", + "start": "npx parcel", + "start:only-this": "npx parcel", + "build:dependencies": "run-s build:dependencies:nym-client-wasm build:dependencies:ts-packages build:dependencies:sdk", + "build:dependencies:nym-client-wasm": "../../packages/nym-client-wasm/scripts/build.sh", + "build:dependencies:ts-packages": "cd ../../../.. && yarn && yarn build", + "build:dependencies:sdk": "cd ../../packages/sdk && yarn build", + "prebuild": "yarn build:dependencies", + "build": "npx parcel build", + "build:only-this": "npx parcel build --log-level info", + "build:serve": "npx serve dist", + "test": "jest", + "test:watch": "jest --watch", + "tsc": "tsc", + "tsc:watch": "tsc --watch", + "lint": "eslint src", + "lint:fix": "eslint src --fix" + } +} diff --git a/sdk/typescript/examples/parcel/src/dom-utils.ts b/sdk/typescript/examples/parcel/src/dom-utils.ts new file mode 100644 index 0000000000..7e98532ea3 --- /dev/null +++ b/sdk/typescript/examples/parcel/src/dom-utils.ts @@ -0,0 +1,62 @@ +import { NymMixnetClient, MimeTypes } from '@nymproject/sdk'; + +/** + * Create a Sphinx packet and send it to the mixnet through the gateway node. + * + * Message and recipient are taken from the values in the user interface. + * + * @param {Client} nymClient the nym client to use for message sending + */ +export async function sendMessageTo(nym: NymMixnetClient) { + const message = (document.getElementById('message') as HTMLFormElement).value; + const recipient = (document.getElementById('recipient') as HTMLFormElement).value; + + await nym.client.send({ payload: { message, mimeType: MimeTypes.TextPlain }, recipient }); + displaySend(message); +} + +/** + * Display messages that have been sent up the websocket. Colours them blue. + * + * @param {string} message + */ +function displaySend(message: string) { + const timestamp = new Date().toISOString().substr(11, 12); + + const sendDiv = document.createElement('div'); + const paragraph = document.createElement('p'); + paragraph.setAttribute('style', 'color: blue'); + const paragraphContent = document.createTextNode(`${timestamp} sent >>> ${message}`); + paragraph.appendChild(paragraphContent); + + sendDiv.appendChild(paragraph); + document.getElementById('output')?.appendChild(sendDiv); +} + +/** + * Display received text messages in the browser. Colour them green. + * + * @param {string} message + */ +export function displayReceived(message: string) { + const content = message; + + const timestamp = new Date().toLocaleTimeString(); + const receivedDiv = document.createElement('div'); + const paragraph = document.createElement('p'); + paragraph.setAttribute('style', 'color: green'); + const paragraphContent = document.createTextNode(`${timestamp} received >>> ${content}`); + // const paragraphContent = document.createTextNode(timestamp + " received >>> " + content + ((replySurb != null) ? "Reply SURB was attached here (but we can't do anything with it yet" : " (NO REPLY-SURB AVAILABLE)")) + paragraph.appendChild(paragraphContent); + receivedDiv.appendChild(paragraph); + document.getElementById('output')?.appendChild(receivedDiv); +} + +/** + * Display the nymClient's sender address in the user interface + * + * @param {Client} nymClient + */ +export function displaySenderAddress(address: string) { + (document.getElementById('sender') as HTMLFormElement).value = address; +} diff --git a/sdk/typescript/examples/parcel/src/index.html b/sdk/typescript/examples/parcel/src/index.html new file mode 100644 index 0000000000..4e4550c539 --- /dev/null +++ b/sdk/typescript/examples/parcel/src/index.html @@ -0,0 +1,36 @@ + + + +
+ + ++ +
+ ++ +
++ +
++ +
+ +Send messages from your browser, through the mixnet, and to the recipient using the "send" button.
+Sent messages show in blue, received + messages show in green.
+ ++
+ + + + diff --git a/sdk/typescript/examples/parcel/src/index.ts b/sdk/typescript/examples/parcel/src/index.ts new file mode 100644 index 0000000000..3871d1c0a7 --- /dev/null +++ b/sdk/typescript/examples/parcel/src/index.ts @@ -0,0 +1,53 @@ +import { createNymMixnetClient, NymMixnetClient } from '@nymproject/sdk'; +import { displayReceived, sendMessageTo, displaySenderAddress } from './dom-utils'; + +let nym: NymMixnetClient | null = null; + +/** + * The main entry point + */ +async function main() { + nym = await createNymMixnetClient(); + + if (!nym) { + console.error('Oh no! Could not create client'); + return; + } + + const nymApiUrl = 'https://validator.nymtech.net/api'; + const preferredGatewayIdentityKey = 'E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM'; + + // subscribe to connect event, so that we can show the client's address + nym.events.subscribeToConnected((e) => { + if (e.args.address) { + displaySenderAddress(e.args.address); + } + }); + + // subscribe to message received events and show any string messages received + nym.events.subscribeToTextMessageReceivedEvent((e) => { + displayReceived(e.args.payload); + }); + + const sendButton: HTMLButtonElement = document.querySelector('#send-button') as HTMLButtonElement; + if (sendButton) { + sendButton.onclick = function () { + if (nym) { + sendMessageTo(nym); + } + }; + } + + // start up the client + await nym.client.start({ + clientId: 'My awesome client', + nymApiUrl, + preferredGatewayIdentityKey, + }); +} + +// wait for the html to load +window.addEventListener('DOMContentLoaded', () => { + // let's do this! + main(); +}); diff --git a/sdk/typescript/examples/parcel/tsconfig.json b/sdk/typescript/examples/parcel/tsconfig.json new file mode 100644 index 0000000000..b8059e8698 --- /dev/null +++ b/sdk/typescript/examples/parcel/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "outDir": "./dist" + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx" + ], + "exclude": [ + "node_modules", + "build", + "dist" + ] +}