Skip to content

Commit

Permalink
Merge pull request #200 from ardriveapp/arweave-fix
Browse files Browse the repository at this point in the history
fix(arweave): modify import of Arweave in `ArweaveToken`
  • Loading branch information
dtfiedler authored Nov 4, 2024
2 parents eb2c99e + b934677 commit 039c914
Show file tree
Hide file tree
Showing 14 changed files with 5,234 additions and 1 deletion.
23 changes: 23 additions & 0 deletions examples/vite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
54 changes: 54 additions & 0 deletions examples/vite/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Typescript React Example - Vite

This example shows how to use the `@ardrive/turbo-sdk` within a Typescript/React project using [Vite].

## Getting Started

1. Install the dependencies:

```bash
yarn
```

2. Start the development server:

```bash
yarn start
```

3. Open your browser and navigate to `http://localhost:3000`. You should see:

![screenshot](./public/screenshot.png)

## Polyfills

The `@ar.io/sdk` uses some modern browser features that may not be available in all browsers. To ensure compatibility, you may need to include some polyfills. This example uses the [vite-plugin-node-polyfills] plugin to include the necessary polyfills.

The [tsconfig.json](./tsconfig.json) includes the following compiler options:

```json
{
"compilerOptions": {
"moduleResolution": "Bundler", // or nodenext are recommended to use named exports (e.g. @ardrive/turbo-sdk/web)
"lib": ["es2015", "dom"]
}
}
```

The [vite.config.js](./vite.config.js) file includes the following polyfills required for the `@ardrive/turbo-sdk`:

```javascript
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import { nodePolyfills } from 'vite-plugin-node-polyfills';

export default defineConfig({
build: {},
base: '/',
plugins: [react(), nodePolyfills()],
});
```

If you are using a bundler other than Vite, you may need to include the necessary polyfills in a similar way.

[vite-plugin-node-polyfills]: https://www.npmjs.com/package/vite-plugin-node-polyfills
18 changes: 18 additions & 0 deletions examples/vite/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
31 changes: 31 additions & 0 deletions examples/vite/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "react-typescript-vite",
"version": "0.1.0",
"private": true,
"dependencies": {
"@ardrive/turbo-sdk": "^1.19.2",
"arweave": "^1.15.5",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.96",
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.2.1",
"starknet": "^6.11.0",
"typescript": "^5.3.3",
"vite": "^5.2.14",
"vite-plugin-html": "^3.2.2",
"vite-plugin-node-polyfills": "^0.22.0"
},
"scripts": {
"start": "vite --config vite.config.js",
"build": "vite build --config vite.config.js",
"postinstall": "yarn link @ardrive/turbo-sdk"
}
}
Binary file added examples/vite/public/favicon.ico
Binary file not shown.
11 changes: 11 additions & 0 deletions examples/vite/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.App {
text-align: center;
background-color: #f0f0f0;
}

.markdown {
text-align: left;
margin: auto;
padding: 50px;
color: white;
}
9 changes: 9 additions & 0 deletions examples/vite/src/App.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { render, screen } from '@testing-library/react';

import App from './App';

test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
161 changes: 161 additions & 0 deletions examples/vite/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import {
TurboAuthenticatedClient,
TurboFactory,
developmentTurboConfiguration,
} from '@ardrive/turbo-sdk/web';
import Arweave from 'arweave';
import { JWKInterface } from 'arweave/node/lib/wallet';
import { useEffect, useState } from 'react';
import { ReadableStream } from 'web-streams-polyfill';

import './App.css';

const arweave = new Arweave({
host: 'arweave.net',
port: 443,
protocol: 'https',
});

const fileToReadableStream = (file: File): ReadableStream => {
const fileReader = new FileReader();
const stream = new ReadableStream({
start(controller) {
fileReader.addEventListener('load', () =>
controller.enqueue(fileReader.result as ArrayBuffer),
);
},
});
return stream;
};

function App() {
const [wallet, setWallet] = useState<JWKInterface | null>(null);
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [uploadStatus, setUploadStatus] = useState<string>('');
const [jwk, setJwk] = useState<string>('');
const [address, setAddress] = useState<string>('');
const [showJwkInput, setShowJwkInput] = useState(true);
const [turbo, setTurbo] = useState<TurboAuthenticatedClient | null>(null);

const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
setSelectedFile(file);
setUploadStatus('');
}
};

const handleUpload = async (event: React.FormEvent) => {
event.preventDefault();

if (!selectedFile) {
setUploadStatus('Please select a file first');
return;
}

if (!wallet) {
setUploadStatus('Please generate a wallet first');
return;
}

if (!turbo) {
setUploadStatus('Please generate a turbo client first');
return;
}

try {
setUploadStatus('Uploading...');
console.log(selectedFile);
const upload = await turbo.uploadFile({
fileStreamFactory: () => fileToReadableStream(selectedFile),
fileSizeFactory: () => selectedFile.size,
});
console.log(upload);
setUploadStatus(`Upload successful! ${JSON.stringify(upload, null, 2)}`);
} catch (error) {
setUploadStatus(
`Upload failed: ${
error instanceof Error ? error.message : 'Unknown error'
}`,
);
}
};

const generateRandomJwk = async () => {
try {
// Generate a random JWK
const jwk = await arweave.wallets.generate();
const address = await arweave.wallets.getAddress(jwk);
setJwk(JSON.stringify(jwk));
setAddress(address);
setShowJwkInput(false);
} catch (error) {
console.error('Error generating JWK:', error);
}
};

const handleJwkChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setJwk(event.target.value);
};

useEffect(() => {
if (jwk) {
setWallet(JSON.parse(jwk));
setTurbo(
TurboFactory.authenticated({
...developmentTurboConfiguration,
privateKey: JSON.parse(jwk),
}),
);
}
}, [jwk]);

return (
<div
className="App flex flex-col items-center"
style={{ padding: '50px', height: '100vh' }}
>
<div
className="flex flex-col items-center"
style={{
marginBottom: '20px',
height: '100%',
}}
>
<h2>File Upload with Turbo SDK</h2>

{showJwkInput ? (
<div style={{ marginBottom: '20px' }}>
<textarea
placeholder="Paste your JWK here..."
value={jwk}
onChange={handleJwkChange}
style={{ width: '300px', height: '100px', marginRight: '10px' }}
/>
<button onClick={generateRandomJwk}>Generate Random JWK</button>
</div>
) : (
<div style={{ marginBottom: '10px' }}>
<p>Using generated JWK - {address}</p>
<button onClick={() => setShowJwkInput(true)}>
Use Different JWK
</button>
</div>
)}

<form onSubmit={handleUpload}>
<input
type="file"
onChange={handleFileSelect}
style={{ marginRight: '10px' }}
/>
<button type="submit">Upload File</button>
</form>

{uploadStatus && <p style={{ marginTop: '10px' }}>{uploadStatus}</p>}
</div>
</div>
);
}

export default App;
14 changes: 14 additions & 0 deletions examples/vite/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #f0f0f0;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
14 changes: 14 additions & 0 deletions examples/vite/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import ReactDOM from 'react-dom/client';

import App from './App';
import './index.css';

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement,
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
21 changes: 21 additions & 0 deletions examples/vite/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"isolatedModules": true,
"jsx": "react-jsx",
"paths": {
"buffer/": ["./node_modules/vite-plugin-node-polyfills/shims/buffer"]
}
},
"include": ["src"]
}
21 changes: 21 additions & 0 deletions examples/vite/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import react from '@vitejs/plugin-react';
import path from 'path';
import { defineConfig } from 'vite';
import { nodePolyfills } from 'vite-plugin-node-polyfills';

export default defineConfig({
base: '/',
plugins: [react(), nodePolyfills()],
resolve: {
alias: {
buffer: path.resolve(
__dirname,
'node_modules/vite-plugin-node-polyfills/shims/buffer',
),
'buffer/': path.resolve(
__dirname,
'node_modules/vite-plugin-node-polyfills/shims/buffer',
),
},
},
});
Loading

0 comments on commit 039c914

Please sign in to comment.