├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── pull_request_template.md └── workflows │ ├── build_release.yml │ ├── main.yml │ └── release_candidate.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── Dockerfile.buildbase ├── Dockerfile.buildruntime ├── LICENSE ├── README.md ├── css ├── hyperware.base64 ├── hyperware.css ├── hyperware.svg └── uno.config.ts ├── entitlements.plist ├── hyperdrive ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── packages │ ├── app-store │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── api │ │ │ └── app-store:sys-v1.wit │ │ ├── app-store │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── http_api.rs │ │ │ │ ├── icon │ │ │ │ ├── lib.rs │ │ │ │ ├── state.rs │ │ │ │ └── utils.rs │ │ ├── chain │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── download │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── downloads │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── ft_worker_lib.rs │ │ │ │ └── lib.rs │ │ ├── ft-worker │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── ft_worker_lib.rs │ │ │ │ └── lib.rs │ │ ├── install │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── metadata.json │ │ ├── pkg │ │ │ ├── manifest.json │ │ │ └── scripts.json │ │ ├── reset-store │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── ui │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── build.sh │ │ │ ├── index.html │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── abis │ │ │ │ │ ├── helpers.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── components │ │ │ │ │ ├── AppCard.tsx │ │ │ │ │ ├── Header.tsx │ │ │ │ │ ├── ManifestDisplay.tsx │ │ │ │ │ ├── MirrorSelector.tsx │ │ │ │ │ ├── NotificationBay.tsx │ │ │ │ │ ├── PackageSelector.tsx │ │ │ │ │ ├── ResetButton.tsx │ │ │ │ │ ├── Tooltip.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── constants │ │ │ │ │ ├── http.ts │ │ │ │ │ └── path.ts │ │ │ │ ├── declarations.d.ts │ │ │ │ ├── index.css │ │ │ │ ├── main.tsx │ │ │ │ ├── pages │ │ │ │ │ ├── AppPage.tsx │ │ │ │ │ ├── DownloadPage.tsx │ │ │ │ │ ├── MyAppsPage.tsx │ │ │ │ │ ├── PublishPage.tsx │ │ │ │ │ └── StorePage.tsx │ │ │ │ ├── store │ │ │ │ │ └── index.ts │ │ │ │ ├── types │ │ │ │ │ └── Apps.ts │ │ │ │ ├── utils │ │ │ │ │ ├── colors.ts │ │ │ │ │ ├── compareVersions.ts │ │ │ │ │ ├── dnsWire.ts │ │ │ │ │ ├── hyperhash.ts │ │ │ │ │ └── ws.ts │ │ │ │ └── vite-env.d.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ ├── uno.config.ts │ │ │ └── vite.config.ts │ │ └── uninstall │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── contacts │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── api │ │ │ └── contacts:sys-v0.wit │ │ ├── contacts │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── icon │ │ │ │ └── lib.rs │ │ ├── get-names │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── metadata.json │ │ └── pkg │ │ │ ├── manifest.json │ │ │ ├── scripts.json │ │ │ └── ui │ │ │ ├── index.html │ │ │ └── script.js │ ├── hns-indexer │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── api │ │ │ └── hns-indexer:sys-v0.wit │ │ ├── get-block │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── hns-indexer │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── metadata.json │ │ ├── node-info │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── pkg │ │ │ ├── manifest.json │ │ │ └── scripts.json │ │ ├── reset │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── state │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ ├── homepage │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── api │ │ │ └── homepage:sys-v1.wit │ │ ├── homepage │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── metadata.json │ │ ├── pkg │ │ │ ├── h-green.svg │ │ │ ├── h-plain.svg │ │ │ ├── hyperware.css │ │ │ ├── hyperware.svg │ │ │ └── manifest.json │ │ └── ui │ │ │ ├── .eslintrc.cjs │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── build.sh │ │ │ ├── index.html │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── src │ │ │ ├── components │ │ │ │ ├── AllApps.tsx │ │ │ │ ├── AppDisplay.tsx │ │ │ │ ├── HyperwareLogo.tsx │ │ │ │ ├── Modal.tsx │ │ │ │ ├── Widget.tsx │ │ │ │ ├── Widgets.tsx │ │ │ │ └── WidgetsSettingsModal.tsx │ │ │ ├── index.css │ │ │ ├── main.tsx │ │ │ ├── pages │ │ │ │ └── Homepage.tsx │ │ │ ├── store │ │ │ │ ├── homepageStore.ts │ │ │ │ └── persistentStore.ts │ │ │ └── vite-env.d.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ ├── uno.config.ts │ │ │ └── vite.config.ts │ ├── settings │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── api │ │ │ └── settings:sys-v0.wit │ │ ├── metadata.json │ │ ├── pkg │ │ │ └── manifest.json │ │ ├── settings │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── icon │ │ │ │ └── lib.rs │ │ └── ui │ │ │ ├── .gitignore │ │ │ ├── index.html │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── src │ │ │ ├── App.tsx │ │ │ ├── abis │ │ │ │ ├── helpers.ts │ │ │ │ └── index.ts │ │ │ ├── components │ │ │ │ └── EditNote.tsx │ │ │ ├── index.css │ │ │ ├── main.tsx │ │ │ └── vite-env.d.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ ├── sign │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── api │ │ │ └── sign:sys-v0.wit │ │ ├── metadata.json │ │ ├── pkg │ │ │ └── manifest.json │ │ └── sign │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ ├── icon │ │ │ └── lib.rs │ ├── terminal │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── alias │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── api │ │ │ └── terminal:sys-v0.wit │ │ ├── cat │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── echo │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── help │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── hfetch │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── hi │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── kill │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── m │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── metadata.json │ │ ├── net-diagnostics │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── peer │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── peers │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── pkg │ │ │ ├── manifest.json │ │ │ └── scripts.json │ │ ├── terminal │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ └── top │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ └── lib.rs │ └── tester │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── api │ │ └── tester:sys-v0.wit │ │ ├── metadata.json │ │ ├── pkg │ │ └── manifest.json │ │ ├── tester │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── lib.rs │ │ │ └── tester_lib.rs │ │ └── tester_lib.rs └── src │ ├── eth │ ├── default_providers_mainnet.json │ ├── mod.rs │ ├── subscription.rs │ └── utils.rs │ ├── fakenet.rs │ ├── fd_manager.rs │ ├── http │ ├── client.rs │ ├── login.html │ ├── mod.rs │ ├── server.rs │ └── utils.rs │ ├── kernel │ ├── mod.rs │ ├── process.rs │ └── standard_host_v1.rs │ ├── keygen.rs │ ├── kv.rs │ ├── main.rs │ ├── net │ ├── connect.rs │ ├── indirect.rs │ ├── mod.rs │ ├── tcp │ │ ├── mod.rs │ │ └── utils.rs │ ├── types.rs │ ├── utils.rs │ └── ws │ │ ├── mod.rs │ │ └── utils.rs │ ├── register-ui │ ├── .gitignore │ ├── .nvmrc │ ├── build.sh │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── robots.txt │ ├── src │ │ ├── App.tsx │ │ ├── abis │ │ │ ├── helpers.ts │ │ │ └── index.ts │ │ ├── components │ │ │ ├── BackButton.tsx │ │ │ ├── DirectCheckbox.tsx │ │ │ ├── DirectTooltip.tsx │ │ │ ├── EnterHnsName.tsx │ │ │ ├── Header.tsx │ │ │ ├── HyperdriveTitle.tsx │ │ │ ├── Loader.tsx │ │ │ ├── ProgressBar.tsx │ │ │ └── Tooltip.tsx │ │ ├── declarations.d.ts │ │ ├── hyperware.css │ │ ├── index.css │ │ ├── index.tsx │ │ ├── lib │ │ │ └── types.ts │ │ ├── pages │ │ │ ├── CommitDotOsName.tsx │ │ │ ├── HyperdriveHome.tsx │ │ │ ├── ImportKeyfile.tsx │ │ │ ├── Login.tsx │ │ │ ├── MintCustom.tsx │ │ │ ├── MintDotOsName.tsx │ │ │ ├── ResetName.tsx │ │ │ └── SetPassword.tsx │ │ ├── utils │ │ │ ├── download-keyfile.ts │ │ │ ├── hns_encoding.ts │ │ │ ├── hyperhash.ts │ │ │ └── redirect-to-homepage.ts │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── uno.config.ts │ └── vite.config.ts │ ├── register.rs │ ├── sol.rs │ ├── sqlite.rs │ ├── state.rs │ ├── terminal │ ├── mod.rs │ └── utils.rs │ ├── timer.rs │ └── vfs.rs ├── lib ├── Cargo.toml ├── build.rs └── src │ ├── core.rs │ ├── eth.rs │ ├── fd_manager.rs │ ├── http │ ├── client_types.rs │ ├── mod.rs │ └── server_types.rs │ ├── kernel.rs │ ├── kv.rs │ ├── lib.rs │ ├── net.rs │ ├── sqlite.rs │ ├── state.rs │ ├── timer.rs │ └── vfs.rs ├── scripts ├── build-packages │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── build-release.py └── build-windows-artifact.py └── src └── lib.rs /.dockerignore: -------------------------------------------------------------------------------- 1 | target/ 2 | wit/ 3 | **/target/ 4 | **/wit/ 5 | **/*.wasm 6 | .vscode 7 | .app-signing 8 | .DS_Store 9 | *.swp 10 | *.swo 11 | *.zip 12 | /home 13 | packages/**/pkg/*.wasm 14 | packages/**/wit 15 | */**/node_modules 16 | .env 17 | hyperdrive/src/bootstrapped_processes.rs 18 | hyperdrive/packages/**/wasi_snapshot_preview1.wasm 19 | 20 | LICENSE 21 | pull_request_template.md 22 | README.md 23 | Dockerfile 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: 'bug: ' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - hyperdrive version [e.g. v1.0.0] 30 | - process_lib version [e.g. v1.0.0] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: 'feature: ' 5 | labels: 'enhancement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Problem 2 | 3 | {A brief description of the problem, along with necessary context.} 4 | 5 | ## Solution 6 | 7 | {A brief description of how you solved the problem.} 8 | 9 | ## Testing 10 | 11 | ``` 12 | # Follow these steps to test 13 | ``` 14 | 15 | ## Docs Update 16 | 17 | [Corresponding docs PR](https://github.com/hyperware-ai/hyperware-book/pull/my-pr-number) 18 | 19 | ## Notes 20 | 21 | {Any other information useful for reviewers.} 22 | -------------------------------------------------------------------------------- /.github/workflows/build_release.yml: -------------------------------------------------------------------------------- 1 | name: rust tagged release in main CI 2 | 3 | on: 4 | push: 5 | tags: ['v[0-9].[0-9]+.[0-9]+'] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | timeout-minutes: 60 11 | 12 | steps: 13 | - name: build and deploy hypedriver 14 | uses: appleboy/ssh-action@master 15 | with: 16 | host: ${{ secrets.SSH_PROD_API_HOST }} 17 | username: ${{ secrets.SSH_PROD_USER }} 18 | key: ${{ secrets.SSH_PROD_API_ED25519KEY }} 19 | port: ${{ secrets.SSH_PROD_PORT }} 20 | command_timeout: 60m 21 | script: | 22 | curl -X PUT http://localhost:8000/monitor/build-hyperdrive 23 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Rustfmt 2 | 3 | on: push 4 | 5 | jobs: 6 | format: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: dtolnay/rust-toolchain@nightly 11 | with: 12 | components: rustfmt 13 | - uses: mbrobbel/rustfmt-check@master 14 | with: 15 | token: ${{ secrets.GITHUB_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/release_candidate.yml: -------------------------------------------------------------------------------- 1 | name: rust release-candidate CI 2 | 3 | on: 4 | push: 5 | branches: [ release-candidate ] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | timeout-minutes: 60 11 | 12 | steps: 13 | - name: build and deploy hyperdrive 14 | uses: appleboy/ssh-action@master 15 | with: 16 | host: ${{ secrets.SSH_API_HOST }} 17 | username: ${{ secrets.SSH_USER }} 18 | key: ${{ secrets.SSH_API_ED25519KEY }} 19 | port: ${{ secrets.SSH_PORT }} 20 | command_timeout: 60m 21 | script: | 22 | curl -X PUT http://localhost:8000/monitor/build-hyperdrive 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | wit/ 3 | **/target/ 4 | **/wit/ 5 | **/wit-*/ 6 | **/*.wasm 7 | .vscode 8 | .app-signing 9 | .DS_Store 10 | *.swp 11 | *.swo 12 | *.zip 13 | /home 14 | */**/node_modules 15 | .env 16 | hyperdrive/src/bootstrapped_processes.rs 17 | hyperdrive/packages/**/wasi_snapshot_preview1.wasm 18 | 19 | hyperdrive/packages/app-store/pkg/ui/* 20 | hyperdrive/packages/homepage/pkg/ui/* 21 | hyperdrive/packages/settings/pkg/ui/* 22 | hyperdrive/src/register-ui/build/ 23 | hyperdrive/src/register-ui/dist/ 24 | hyperdrive/packages/docs/pkg/ui 25 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hyperdrive_lib" 3 | authors = ["Sybil Technologies AG"] 4 | version = "1.2.1" 5 | edition = "2021" 6 | description = "A general-purpose sovereign cloud computing platform" 7 | homepage = "https://hyperware.ai" 8 | repository = "https://github.com/hyperware-ai/hyperdrive" 9 | license = "Apache-2.0" 10 | 11 | [dependencies] 12 | lib = { path = "lib" } 13 | 14 | [workspace] 15 | members = [ 16 | "lib", "hyperdrive", 17 | "hyperdrive/packages/app-store/app-store", "hyperdrive/packages/app-store/ft-worker", 18 | "hyperdrive/packages/app-store/downloads", "hyperdrive/packages/app-store/chain", 19 | "hyperdrive/packages/app-store/download", "hyperdrive/packages/app-store/install", "hyperdrive/packages/app-store/uninstall", "hyperdrive/packages/app-store/reset-store", 20 | "hyperdrive/packages/contacts/contacts", 21 | "hyperdrive/packages/homepage/homepage", 22 | "hyperdrive/packages/hns-indexer/hns-indexer", "hyperdrive/packages/hns-indexer/get-block", "hyperdrive/packages/settings/settings", "hyperdrive/packages/hns-indexer/reset", 23 | "hyperdrive/packages/hns-indexer/node-info", "hyperdrive/packages/hns-indexer/state", 24 | "hyperdrive/packages/sign/sign", 25 | "hyperdrive/packages/terminal/terminal", 26 | "hyperdrive/packages/terminal/alias", "hyperdrive/packages/terminal/cat", "hyperdrive/packages/terminal/echo", 27 | "hyperdrive/packages/terminal/help", "hyperdrive/packages/terminal/hfetch", "hyperdrive/packages/terminal/hi", 28 | "hyperdrive/packages/terminal/kill", "hyperdrive/packages/terminal/m", "hyperdrive/packages/terminal/top", 29 | "hyperdrive/packages/terminal/net-diagnostics", "hyperdrive/packages/terminal/peer", "hyperdrive/packages/terminal/peers", 30 | "hyperdrive/packages/tester/tester", 31 | "scripts/build-packages", 32 | ] 33 | default-members = ["lib"] 34 | resolver = "2" 35 | 36 | [profile.release] 37 | strip = "symbols" 38 | lto = true 39 | panic = "abort" 40 | codegen-units = 1 41 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=$BUILDPLATFORM alpine AS downloader_start 2 | ARG VERSION 3 | ARG TARGETARCH 4 | WORKDIR /tmp/download 5 | RUN apk update && apk add unzip wget --no-cache 6 | 7 | FROM downloader_start AS downloader_amd64 8 | ADD "https://github.com/hyperware-ai/hyperdrive/releases/download/${VERSION}/hyperdrive-x86_64-unknown-linux-gnu.zip" hyperdrive-x86_64-unknown-linux-gnu.zip 9 | RUN unzip hyperdrive-x86_64-unknown-linux-gnu.zip 10 | 11 | FROM downloader_start AS downloader_arm64 12 | ADD "https://github.com/hyperware-ai/hyperdrive/releases/download/${VERSION}/hyperdrive-aarch64-unknown-linux-gnu.zip" hyperdrive-aarch64-unknown-linux-gnu.zip 13 | RUN unzip hyperdrive-aarch64-unknown-linux-gnu.zip 14 | 15 | FROM downloader_${TARGETARCH} AS downloader 16 | 17 | FROM debian:12-slim 18 | 19 | # Create a non-root user and group 20 | RUN groupadd -r hyperdrive && \ 21 | useradd -r -g hyperdrive -d /hyperdrive-home/home/hyperdrive hyperdrive 22 | 23 | RUN apt-get update && \ 24 | apt-get install openssl -y && \ 25 | rm -rf /var/lib/apt/lists/* 26 | 27 | # Create directory for hyperdrive and set permissions 28 | RUN mkdir -p /hyperdrive-home/home/hyperdrive && \ 29 | chown -R hyperdrive:hyperdrive /hyperdrive-home 30 | 31 | COPY --from=downloader /tmp/download/hyperdrive /bin/hyperdrive 32 | RUN chown hyperdrive:hyperdrive /bin/hyperdrive && \ 33 | chmod 755 /bin/hyperdrive 34 | 35 | # Switch to non-root user 36 | USER hyperdrive 37 | 38 | WORKDIR /hyperdrive-home 39 | 40 | ENTRYPOINT [ "/bin/hyperdrive" ] 41 | CMD [ "/hyperdrive-home" ] 42 | 43 | EXPOSE 8080 44 | EXPOSE 9000 45 | EXPOSE 10000 46 | -------------------------------------------------------------------------------- /Dockerfile.buildbase: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | # Set environment variables to avoid interactive dialog from APT 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | ENV NVM_DIR=/root/.nvm 6 | 7 | # Install all necessary packages in one layer and clean up in the same layer 8 | RUN apt-get update && apt-get install -y --no-install-recommends \ 9 | build-essential \ 10 | pkg-config \ 11 | ca-certificates \ 12 | libssl-dev \ 13 | cmake \ 14 | llvm-dev \ 15 | libclang-dev \ 16 | clang \ 17 | curl \ 18 | git \ 19 | python3 \ 20 | && update-ca-certificates \ 21 | && rm -rf /var/lib/apt/lists/* 22 | 23 | # Install Rust and wasm tools 24 | RUN curl https://sh.rustup.rs -sSf | sh -s -- -y \ 25 | && . $HOME/.cargo/env \ 26 | && rustup install nightly \ 27 | && rustup target add wasm32-wasi \ 28 | && rustup target add wasm32-wasi --toolchain nightly \ 29 | && rustup target add wasm32-wasip1 \ 30 | && rustup target add wasm32-wasip1 --toolchain nightly \ 31 | && cargo install wasm-tools \ 32 | && cargo install cargo-wasi \ 33 | && rm -rf ~/.cargo/git \ 34 | && rm -rf ~/.cargo/registry 35 | 36 | # Install NVM, Node.js 37 | RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash \ 38 | && . "$NVM_DIR/nvm.sh" \ 39 | && nvm install node \ 40 | && nvm use node 41 | 42 | # Set up environment variables 43 | ENV DEBIAN_FRONTEND=dialog \ 44 | PATH="/root/.nvm/versions/node/$(node -v)/bin:${PATH}" 45 | 46 | # Set the default command to bash 47 | CMD ["bash"] 48 | -------------------------------------------------------------------------------- /Dockerfile.buildruntime: -------------------------------------------------------------------------------- 1 | FROM nick1udwig/buildbase:latest 2 | 3 | ARG DOCKER_BUILD_IMAGE_VERSION=latest 4 | 5 | ENV NVM_DIR=/root/.nvm \ 6 | PATH="/root/.nvm/versions/node/$(node -v)/bin:${PATH}" \ 7 | DOCKER_BUILD_IMAGE_VERSION=$DOCKER_BUILD_IMAGE_VERSION 8 | 9 | # Bind readonly & copy files in to avoid modifying host files 10 | WORKDIR /input 11 | 12 | # Set the default command to run the build script 13 | CMD ["/bin/bash", "-c", ". ~/.bashrc && . ~/.cargo/env && . $NVM_DIR/nvm.sh && ./scripts/build-release.py && cp -r /tmp/hyperdrive-release/* /output && chmod 664 /output/* && [ '$(id -u)' != '0' ] && find . -user root -print0 2>/dev/null | xargs -0 rm -rf"] 14 | -------------------------------------------------------------------------------- /css/hyperware.base64: -------------------------------------------------------------------------------- 1 | PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMiIg 2 | ZGF0YS1uYW1lPSJMYXllciAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZp 3 | ZXdCb3g9IjAgMCA2MjIuMjcgNTk1LjA5Ij4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgQG1l 4 | ZGlhIChwcmVmZXJzLWNvbG9yLXNjaGVtZTogZGFyaykgewogICAgICAgIC5jbHMtMSB7CiAgICAg 5 | ICAgICBmaWxsOiAjZGNmZjcxOwogICAgICAgIH0KICAgICAgfQogICAgICBAbWVkaWEgKHByZWZl 6 | cnMtY29sb3Itc2NoZW1lOiBsaWdodCkgewogICAgICAgIC5jbHMtMSB7CiAgICAgICAgICBmaWxs 7 | OiAjMDA0ZmZmOwogICAgICAgIH0KICAgICAgfQogICAgPC9zdHlsZT4KICA8L2RlZnM+CiAgPGcg 8 | aWQ9IkNhcGFfMSIgZGF0YS1uYW1lPSJDYXBhIDEiPgogICAgPGc+CiAgICAgIDxnPgogICAgICAg 9 | IDxnPgogICAgICAgICAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNOTkuNTYsMTg4LjIxTDAsNDc2 10 | LjI3bDkzLjU2LjAzYzEwLjgsMCwyMC40LTYuODQsMjMuOTMtMTcuMDVsNTMuNTktMTU1LjA3YzMu 11 | NzktMTAuOTcsMS43My0yMy4xMS01LjQ1LTMyLjIybC02Ni4wNi04My43NloiLz4KICAgICAgICAg 12 | IDxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTQyMC43OCwxMTguODJsLTMwLjE0LDg3LjFjLTMuNzQs 13 | MTAuOC0xMy45MSwxOC4wNC0yNS4zNCwxOC4wNGgtNzAuNDhjLTEwLjQ2LDAtMjAuMzQtNC43Ni0y 14 | Ni44MS0xMi45N2wtNzIuNjctOTIuMTdoMjI1LjQ0WiIvPgogICAgICAgIDwvZz4KICAgICAgICA8 15 | cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0xMDEuNjMsMGwtNDIuNzQsMTIzLjYxYy0xLjg1LDUuMzUt 16 | Ljk5LDExLjI4LDIuMywxNS45M2wzOC4zNyw0OC42NywxNy42OS01MS4xNmMzLjc3LTEwLjkxLDE0 17 | LjA1LTE4LjIzLDI1LjU5LTE4LjIzaDUyLjVMMTAxLjYzLDBaIi8+CiAgICAgIDwvZz4KICAgICAg 18 | PGc+CiAgICAgICAgPGc+CiAgICAgICAgICA8cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik01MjIuNzEs 19 | NDA2Ljg4bDk5LjU2LTI4OC4wNi05My41Ni0uMDNjLTEwLjgsMC0yMC40LDYuODQtMjMuOTMsMTcu 20 | MDVsLTUzLjU5LDE1NS4wN2MtMy43OSwxMC45Ny0xLjczLDIzLjExLDUuNDUsMzIuMjJsNjYuMDYs 21 | ODMuNzZaIi8+CiAgICAgICAgICA8cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0yMDEuNDksNDc2LjI3 22 | bDMwLjE0LTg3LjFjMy43NC0xMC44LDEzLjkxLTE4LjA0LDI1LjM0LTE4LjA0aDcwLjQ4YzEwLjQ2 23 | LDAsMjAuMzQsNC43NiwyNi44MSwxMi45N2w3Mi42Nyw5Mi4xN2gtMjI1LjQ0WiIvPgogICAgICAg 24 | IDwvZz4KICAgICAgICA8cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik01MjAuNjQsNTk1LjA5bDQyLjc0 25 | LTEyMy42MWMxLjg1LTUuMzUuOTktMTEuMjgtMi4zLTE1LjkzbC0zOC4zNy00OC42Ny0xNy42OSw1 26 | MS4xNmMtMy43NywxMC45MS0xNC4wNSwxOC4yMy0yNS41OSwxOC4yM2gtNTIuNWw5My43MSwxMTgu 27 | ODJaIi8+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPg== 28 | -------------------------------------------------------------------------------- /css/hyperware.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.cs.allow-unsigned-executable-memory 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /hyperdrive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hyperdrive" 3 | authors = ["Sybil Technologies AG"] 4 | version = "1.2.1" 5 | edition = "2021" 6 | description = "A general-purpose sovereign cloud computing platform" 7 | homepage = "https://hyperware.ai" 8 | repository = "https://github.com/hyperware-ai/hyperdrive" 9 | license = "Apache-2.0" 10 | 11 | [[bin]] 12 | name = "hyperdrive" 13 | path = "src/main.rs" 14 | 15 | [build-dependencies] 16 | anyhow = "1.0.71" 17 | sha2 = "0.10.8" 18 | 19 | [features] 20 | simulation-mode = [] 21 | 22 | [dependencies] 23 | aes-gcm = "0.10.3" 24 | alloy = { version = "0.8.1", features = [ 25 | "consensus", 26 | "contract", 27 | "json-rpc", 28 | "network", 29 | "provider-ws", 30 | "providers", 31 | "pubsub", 32 | "rpc", 33 | "rpc-client", 34 | "rpc-client-ws", 35 | "rpc-types", 36 | "rpc-types-eth", 37 | "signers", 38 | "signer-local", 39 | ] } 40 | alloy-primitives = "0.8.15" 41 | alloy-sol-macro = "0.8.15" 42 | alloy-sol-types = "0.8.15" 43 | anyhow = "1.0.71" 44 | argon2 = "0.5.3" 45 | async-trait = "0.1.71" 46 | base64 = "0.22.0" 47 | bincode = "1.3.3" 48 | chrono = "0.4.31" 49 | clap = { version = "4.4", features = ["derive"] } 50 | crossterm = { version = "0.27.0", features = ["event-stream", "bracketed-paste"] } 51 | dashmap = "5.5.3" 52 | futures = "0.3" 53 | generic-array = "0.14.7" 54 | hex = "0.4.3" 55 | hmac = "0.12" 56 | http = "1.1.0" 57 | indexmap = "2.4" 58 | jwt = "0.16" 59 | lib = { path = "../lib" } 60 | lazy_static = "1.4.0" 61 | libc = "0.2" 62 | nohash-hasher = "0.2.0" 63 | open = "5.1.4" 64 | public-ip = "0.2.2" 65 | rand = "0.8.4" 66 | regex = "1.11.0" 67 | reqwest = "0.12.4" 68 | ring = "0.17.8" 69 | rmp-serde = "1.1.2" 70 | rocksdb = { version = "0.22.0", features = ["multi-threaded-cf"] } 71 | route-recognizer = "0.3.1" 72 | rusqlite = { version = "0.31.0", features = ["bundled"] } 73 | serde = { version = "1.0", features = ["derive"] } 74 | serde_json = "1.0" 75 | sha2 = "0.10.8" 76 | # snow = { version = "0.9.5", features = ["ring-resolver"] } 77 | # unfortunately need to use forked version for async use and in-place encryption 78 | snow = { git = "https://github.com/dr-frmr/snow", branch = "dr/extract_cipherstates", features = ["ring-resolver"] } 79 | socket2 = "0.5.7" 80 | static_dir = "0.2.0" 81 | tokio = { version = "1.28", features = ["fs", "macros", "rt-multi-thread", "signal", "sync", "time"] } 82 | tokio-tungstenite = { version = "0.21.0", features = ["native-tls"] } 83 | unicode-segmentation = "1.11" 84 | unicode-width = "0.1.13" 85 | url = "2.4.1" 86 | warp = "0.3.5" 87 | wasmtime = "27.0.0" 88 | wasmtime-wasi = "27.0.0" 89 | zip = "1.1.1" 90 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "app-store", 5 | "chain", 6 | "download", 7 | "downloads", 8 | "ft-worker", 9 | "install", 10 | "uninstall", 11 | "reset-store", 12 | ] 13 | 14 | [profile.release] 15 | panic = "abort" 16 | opt-level = "s" 17 | lto = true 18 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/app-store/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "app-store" 3 | version = "0.3.1" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | alloy-primitives = "0.8.15" 11 | alloy-sol-types = "0.8.15" 12 | anyhow = "1.0" 13 | bincode = "1.3.3" 14 | hyperware_process_lib = "1.0.5" 15 | process_macros = "0.1" 16 | rand = "0.8" 17 | serde = { version = "1.0", features = ["derive"] } 18 | serde_json = "1.0" 19 | sha2 = "0.10.8" 20 | sha3 = "0.10.8" 21 | url = "2.4.1" 22 | urlencoding = "2.1.0" 23 | wit-bindgen = "0.36.0" 24 | zip = { version = "1.1.1", default-features = false } 25 | 26 | [lib] 27 | crate-type = ["cdylib"] 28 | 29 | [package.metadata.component] 30 | package = "hyperware:process" 31 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/chain/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chain" 3 | version = "0.5.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | alloy-primitives = "0.8.15" 11 | alloy-sol-types = "0.8.15" 12 | anyhow = "1.0" 13 | bincode = "1.3.3" 14 | hyperware_process_lib = "1.0.5" 15 | process_macros = "0.1" 16 | rand = "0.8" 17 | serde = { version = "1.0", features = ["derive"] } 18 | serde_json = "1.0" 19 | sha2 = "0.10.8" 20 | sha3 = "0.10.8" 21 | url = "2.4.1" 22 | urlencoding = "2.1.0" 23 | wit-bindgen = "0.36.0" 24 | zip = { version = "1.1.1", default-features = false } 25 | 26 | [lib] 27 | crate-type = ["cdylib"] 28 | 29 | [package.metadata.component] 30 | package = "hyperware:process" 31 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/download/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "download" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | anyhow = "1.0" 11 | hyperware_process_lib = "1.0.5" 12 | process_macros = "0.1" 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | wit-bindgen = "0.36.0" 16 | 17 | [lib] 18 | crate-type = ["cdylib"] 19 | 20 | [package.metadata.component] 21 | package = "hyperware:process" 22 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/download/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! download:app-store:sys 2 | //! terminal script for downloading apps from the app store. 3 | //! 4 | //! Usage: 5 | //! download:app-store:sys 6 | //! 7 | //! Arguments: 8 | //! The node ID to download from (e.g., my-friend.os) 9 | //! The package ID of the app (e.g., app:publisher.os) 10 | //! The version hash of the app to download 11 | //! 12 | //! Example: 13 | //! download:app-store:sys my-friend.os app:publisher.os f5d374ab50e66888a7c2332b22d0f909f2e3115040725cfab98dcae488916990 14 | //! 15 | use crate::hyperware::process::downloads::{DownloadRequest, LocalDownloadRequest}; 16 | use hyperware_process_lib::{ 17 | await_next_message_body, call_init, println, Address, PackageId, Request, 18 | }; 19 | 20 | wit_bindgen::generate!({ 21 | path: "target/wit", 22 | generate_unused_types: true, 23 | world: "app-store-sys-v1", 24 | additional_derives: [PartialEq, serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], 25 | }); 26 | 27 | call_init!(init); 28 | fn init(our: Address) { 29 | let Ok(body) = await_next_message_body() else { 30 | println!("download: failed to get args!"); 31 | return; 32 | }; 33 | 34 | let args = String::from_utf8(body).unwrap_or_default(); 35 | let parts: Vec<&str> = args.split_whitespace().collect(); 36 | if parts.len() != 3 { 37 | println!("download: 3 arguments required, the node id to download from, the package id of the app, and the version hash"); 38 | println!("example: download my-friend.os app:publisher.os f5d374ab50e66888a7c2332b22d0f909f2e3115040725cfab98dcae488916990"); 39 | return; 40 | } 41 | let (arg1, arg2, arg3) = (parts[0], parts[1], parts[2]); 42 | 43 | let download_from: String = arg1.to_string(); 44 | 45 | let Ok(package_id) = arg2.parse::() else { 46 | println!("download: invalid package id, make sure to include package name and publisher"); 47 | println!("example: app_name:publisher_name"); 48 | return; 49 | }; 50 | 51 | let version_hash: String = arg3.to_string(); 52 | 53 | let Ok(_) = Request::to((our.node(), ("downloads", "app-store", "sys"))) 54 | .body(DownloadRequest::LocalDownload(LocalDownloadRequest { 55 | package_id: crate::hyperware::process::main::PackageId { 56 | package_name: package_id.package_name.clone(), 57 | publisher_node: package_id.publisher_node.clone(), 58 | }, 59 | download_from: download_from.clone(), 60 | desired_version_hash: version_hash.clone(), 61 | })) 62 | .send() 63 | else { 64 | println!("download: failed to send request to downloads:app-store!"); 65 | return; 66 | }; 67 | 68 | println!("download: request sent, started download from {download_from}"); 69 | } 70 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/downloads/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "downloads" 3 | version = "0.5.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | anyhow = "1.0" 11 | hyperware_process_lib = "1.0.5" 12 | process_macros = "0.1" 13 | rand = "0.8" 14 | serde = { version = "1.0", features = ["derive"] } 15 | serde_json = "1.0" 16 | sha2 = "0.10.8" 17 | sha3 = "0.10.8" 18 | url = "2.4.1" 19 | urlencoding = "2.1.0" 20 | wit-bindgen = "0.36.0" 21 | zip = { version = "1.1.4", default-features = false, features = ["deflate"] } 22 | 23 | [lib] 24 | crate-type = ["cdylib"] 25 | 26 | [package.metadata.component] 27 | package = "hyperware:process" 28 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/downloads/src/ft_worker_lib.rs: -------------------------------------------------------------------------------- 1 | ../../ft-worker/src/ft_worker_lib.rs -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ft-worker/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ft-worker" 3 | version = "0.2.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | anyhow = "1.0" 11 | bincode = "1.3.3" 12 | hyperware_process_lib = "1.0.5" 13 | process_macros = "0.1" 14 | rand = "0.8" 15 | serde = { version = "1.0", features = ["derive"] } 16 | serde_json = "1.0" 17 | sha2 = "0.10.8" 18 | wit-bindgen = "0.36.0" 19 | zip = { version = "1.1.4", default-features = false, features = ["deflate"] } 20 | 21 | [lib] 22 | crate-type = ["cdylib"] 23 | 24 | [package.metadata.component] 25 | package = "hyperware:process" 26 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/install/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "install" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | anyhow = "1.0" 11 | hyperware_process_lib = "1.0.5" 12 | process_macros = "0.1" 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | wit-bindgen = "0.36.0" 16 | 17 | [lib] 18 | crate-type = ["cdylib"] 19 | 20 | [package.metadata.component] 21 | package = "hyperware:process" 22 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App Store", 3 | "description": "A package manager + app store for Hyperware.", 4 | "image": "", 5 | "properties": { 6 | "package_name": "app-store", 7 | "publisher": "sys", 8 | "current_version": "1.0.0", 9 | "mirrors": [], 10 | "code_hashes": { 11 | "1.0.0": "" 12 | }, 13 | "wit_version": 1, 14 | "dependencies": [] 15 | }, 16 | "external_url": "https://hyperware.ai", 17 | "animation_url": "" 18 | } 19 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/pkg/scripts.json: -------------------------------------------------------------------------------- 1 | { 2 | "download.wasm": { 3 | "root": false, 4 | "public": false, 5 | "request_networking": false, 6 | "request_capabilities": [ 7 | "main:app-store:sys", 8 | "downloads:app-store:sys" 9 | ], 10 | "grant_capabilities": [ 11 | "main:app-store:sys", 12 | "downloads:app-store:sys" 13 | ], 14 | "wit_version": 1 15 | }, 16 | "install.wasm": { 17 | "root": false, 18 | "public": false, 19 | "request_networking": false, 20 | "request_capabilities": [ 21 | "main:app-store:sys" 22 | ], 23 | "grant_capabilities": [ 24 | "main:app-store:sys" 25 | ], 26 | "wit_version": 1 27 | }, 28 | "uninstall.wasm": { 29 | "root": false, 30 | "public": false, 31 | "request_networking": false, 32 | "request_capabilities": [ 33 | "main:app-store:sys" 34 | ], 35 | "grant_capabilities": [ 36 | "main:app-store:sys" 37 | ], 38 | "wit_version": 1 39 | }, 40 | "reset-store.wasm": { 41 | "root": false, 42 | "public": false, 43 | "request_networking": false, 44 | "request_capabilities": [ 45 | "chain:app-store:sys" 46 | ], 47 | "grant_capabilities": [ 48 | "chain:app-store:sys" 49 | ], 50 | "wit_version": 1 51 | } 52 | } -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/reset-store/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "reset-store" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | anyhow = "1.0" 11 | hyperware_process_lib = "1.0.5" 12 | process_macros = "0.1" 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | wit-bindgen = "0.36.0" 16 | 17 | [lib] 18 | crate-type = ["cdylib"] 19 | 20 | [package.metadata.component] 21 | package = "hyperware:process" 22 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/reset-store/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! reset:app-store:sys 2 | //! terminal script for resetting the app store. 3 | //! 4 | //! Usage: 5 | //! reset:app-store:sys 6 | //! 7 | //! Arguments: 8 | //! 9 | //! 10 | use crate::hyperware::process::chain::{ChainRequest, ChainResponse}; 11 | use hyperware_process_lib::{call_init, println, Address, Message, Request}; 12 | 13 | wit_bindgen::generate!({ 14 | path: "target/wit", 15 | generate_unused_types: true, 16 | world: "app-store-sys-v1", 17 | additional_derives: [PartialEq, serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], 18 | }); 19 | 20 | call_init!(init); 21 | fn init(_our: Address) { 22 | // no args 23 | 24 | let Ok(Ok(Message::Response { body, .. })) = Request::to(("our", "chain", "app-store", "sys")) 25 | .body(ChainRequest::Reset) 26 | .send_and_await_response(5) 27 | else { 28 | println!("reset: failed to get a response from app-store..!"); 29 | return; 30 | }; 31 | 32 | let Ok(response) = body.try_into() else { 33 | println!("reset: failed to parse response from app-store..!"); 34 | return; 35 | }; 36 | 37 | match response { 38 | ChainResponse::ResetOk => { 39 | println!("successfully reset app-store"); 40 | } 41 | _ => { 42 | println!("reset: unexpected response from app-store..!"); 43 | return; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/README.md: -------------------------------------------------------------------------------- 1 | # App Store UI 2 | 3 | This UI template uses the React framework compiled with Vite. 4 | It is based on the Vite React Typescript template. 5 | 6 | ## Setup 7 | 8 | There are 2 ways to set up this repo: 9 | 1. Place this repo next to the `pkg` repo of your Hyperware project (usually the top level). 10 | 2. Set `BASE_URL` in `vite.config.ts` to the URL of your Hyperware project (i.e. `/chess:chess:sys`) and comment out lines 8 and 9. 11 | 12 | ## Development 13 | 14 | Run `npm i`, `npm run tc`, and then `npm start` to start working on the UI. 15 | By default, the dev server will proxy requests to `http://localhost:8080`. 16 | You can change the proxy target by setting `VITE_NODE_URL` like so: 17 | `VITE_NODE_URL=http://localhost:8081 npm start` 18 | 19 | You may see an error: 20 | 21 | ``` 22 | [vite] Pre-transform error: Failed to load url /our.js (resolved id: /our.js). Does the file exist? 23 | ``` 24 | 25 | You can safely ignore this error. The file will be served by the node via the proxy. 26 | 27 | #### public vs assets 28 | 29 | The `public/assets` folder contains files that are referenced in `index.html`, `src/assets` is for asset files that are only referenced in `src` code. 30 | 31 | ## Building 32 | 33 | Run `npm run build`, the build will be generated in the `dist` directory. 34 | If this repo is next to your Hyperware `pkg` directory then you can `npm run build:copy` to build and copy it for installation. 35 | 36 | ## About Vite + React 37 | 38 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 39 | 40 | Currently, two official plugins are available: 41 | 42 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 43 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 44 | 45 | ## Expanding the ESLint configuration 46 | 47 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 48 | 49 | - Configure the top-level `parserOptions` property like this: 50 | 51 | ```js 52 | export default { 53 | // other rules... 54 | parserOptions: { 55 | ecmaVersion: 'latest', 56 | sourceType: 'module', 57 | project: ['./tsconfig.json', './tsconfig.node.json'], 58 | tsconfigRootDir: __dirname, 59 | }, 60 | } 61 | ``` 62 | 63 | - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` 64 | - Optionally add `plugin:@typescript-eslint/stylistic-type-checked` 65 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list 66 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/build.sh: -------------------------------------------------------------------------------- 1 | npm install && npm run build:copy -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | App Store 9 | 10 | 11 | 12 | 13 | 40 | 41 | 43 | 44 | 45 | 46 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperware-app-store", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite --port 3000", 8 | "start": "vite --port 3000", 9 | "build": "tsc && vite build", 10 | "copy": "mkdir -p ../pkg/ui && rm -rf ../pkg/ui/* && cp -r dist/* ../pkg/ui/", 11 | "build:copy": "npm run build && npm run copy", 12 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 13 | "preview": "vite preview" 14 | }, 15 | "dependencies": { 16 | "@hyperware-ai/client-api": "^0.1.0", 17 | "@metamask/jazzicon": "^2.0.0", 18 | "@rainbow-me/rainbowkit": "^2.1.2", 19 | "@szhsin/react-menu": "^4.1.0", 20 | "@tanstack/react-query": "^5.45.1", 21 | "classnames": "^2.5.1", 22 | "idna-uts46-hx": "^6.0.4", 23 | "js-sha3": "^0.9.3", 24 | "react": "^18.2.0", 25 | "react-dom": "^18.2.0", 26 | "react-icons": "^5.0.1", 27 | "react-router-dom": "^6.21.3", 28 | "unocss": "^0.59.4", 29 | "viem": "^2.15.1", 30 | "wagmi": "^2.10.3", 31 | "zustand": "^4.4.7" 32 | }, 33 | "devDependencies": { 34 | "@types/node": "^20.10.4", 35 | "@types/react": "^18.2.43", 36 | "@types/react-dom": "^18.2.17", 37 | "@typescript-eslint/eslint-plugin": "^6.14.0", 38 | "@typescript-eslint/parser": "^6.14.0", 39 | "@vitejs/plugin-react": "^4.2.1", 40 | "esbuild": ">0.24.2", 41 | "eslint": "^8.55.0", 42 | "eslint-plugin-react-hooks": "^4.6.0", 43 | "eslint-plugin-react-refresh": "^0.4.5", 44 | "http-proxy-middleware": "^2.0.6", 45 | "rollup": "^4.35.0", 46 | "typechain": "^8.3.1", 47 | "typescript": "^5.2.2", 48 | "vite": "^5.0.8", 49 | "vite-plugin-node-polyfills": "^0.22.0" 50 | }, 51 | "optionalDependencies": { 52 | "@rollup/rollup-android-arm-eabi": "^4.35.0", 53 | "@rollup/rollup-android-arm64": "^4.35.0", 54 | "@rollup/rollup-darwin-arm64": "^4.35.0", 55 | "@rollup/rollup-darwin-x64": "^4.35.0", 56 | "@rollup/rollup-freebsd-arm64": "^4.35.0", 57 | "@rollup/rollup-freebsd-x64": "^4.35.0", 58 | "@rollup/rollup-linux-arm-gnueabihf": "^4.35.0", 59 | "@rollup/rollup-linux-arm-musleabihf": "^4.35.0", 60 | "@rollup/rollup-linux-arm64-gnu": "^4.35.0", 61 | "@rollup/rollup-linux-arm64-musl": "^4.35.0", 62 | "@rollup/rollup-linux-loongarch64-gnu": "^4.35.0", 63 | "@rollup/rollup-linux-powerpc64le-gnu": "^4.35.0", 64 | "@rollup/rollup-linux-riscv64-gnu": "^4.35.0", 65 | "@rollup/rollup-linux-s390x-gnu": "^4.35.0", 66 | "@rollup/rollup-linux-x64-gnu": "^4.35.0", 67 | "@rollup/rollup-linux-x64-musl": "^4.35.0", 68 | "@rollup/rollup-win32-arm64-msvc": "^4.35.0", 69 | "@rollup/rollup-win32-ia32-msvc": "^4.35.0", 70 | "@rollup/rollup-win32-x64-msvc": "^4.35.0" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { BrowserRouter as Router, Route, Routes } from "react-router-dom"; 3 | 4 | import Header from "./components/Header"; 5 | import { APP_DETAILS_PATH, DOWNLOAD_PATH, MY_APPS_PATH, PUBLISH_PATH, STORE_PATH } from "./constants/path"; 6 | 7 | import StorePage from "./pages/StorePage"; 8 | import AppPage from "./pages/AppPage"; 9 | import DownloadPage from "./pages/DownloadPage"; 10 | import PublishPage from "./pages/PublishPage"; 11 | import MyAppsPage from "./pages/MyAppsPage"; 12 | 13 | 14 | const BASE_URL = import.meta.env.BASE_URL; 15 | if (window.our) window.our.process = BASE_URL?.replace("/", ""); 16 | 17 | function App() { 18 | 19 | return ( 20 |
21 | 22 |
23 | 24 | } /> 25 | } /> 26 | } /> 27 | } /> 28 | } /> 29 | 30 | 31 |
32 | ); 33 | } 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/abis/helpers.ts: -------------------------------------------------------------------------------- 1 | import { multicallAbi, hypermapAbi, mechAbi, HYPERMAP, MULTICALL, HYPER_ACCOUNT_UPGRADABLE_IMPL } from "./"; 2 | import { encodeFunctionData, encodePacked, stringToHex } from "viem"; 3 | 4 | export function encodeMulticalls(metadataUri: string, metadataHash: string) { 5 | const metadataHashCall = encodeFunctionData({ 6 | abi: hypermapAbi, 7 | functionName: 'note', 8 | args: [ 9 | encodePacked(["bytes"], [stringToHex("~metadata-hash")]), 10 | encodePacked(["bytes"], [stringToHex(metadataHash)]), 11 | ] 12 | }) 13 | 14 | const metadataUriCall = encodeFunctionData({ 15 | abi: hypermapAbi, 16 | functionName: 'note', 17 | args: [ 18 | encodePacked(["bytes"], [stringToHex("~metadata-uri")]), 19 | encodePacked(["bytes"], [stringToHex(metadataUri)]), 20 | ] 21 | }) 22 | 23 | const calls = [ 24 | { target: HYPERMAP, callData: metadataHashCall }, 25 | { target: HYPERMAP, callData: metadataUriCall }, 26 | ]; 27 | 28 | const multicall = encodeFunctionData({ 29 | abi: multicallAbi, 30 | functionName: 'aggregate', 31 | args: [calls] 32 | }); 33 | return multicall; 34 | } 35 | 36 | export function encodeIntoMintCall(multicalls: `0x${string}`, our_address: `0x${string}`, app_name: string) { 37 | const initCall = encodeFunctionData({ 38 | abi: mechAbi, 39 | functionName: 'execute', 40 | args: [ 41 | MULTICALL, 42 | BigInt(0), 43 | multicalls, 44 | 1 45 | ] 46 | }); 47 | 48 | const mintCall = encodeFunctionData({ 49 | abi: hypermapAbi, 50 | functionName: 'mint', 51 | args: [ 52 | our_address, 53 | encodePacked(["bytes"], [stringToHex(app_name)]), 54 | initCall, 55 | HYPER_ACCOUNT_UPGRADABLE_IMPL, 56 | ] 57 | }) 58 | return mintCall; 59 | } 60 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/abis/index.ts: -------------------------------------------------------------------------------- 1 | import { parseAbi } from "viem"; 2 | 3 | export { encodeMulticalls, encodeIntoMintCall } from "./helpers"; 4 | 5 | export const HYPERMAP: `0x${string}` = "0x000000000044C6B8Cb4d8f0F889a3E47664EAeda"; 6 | export const MULTICALL: `0x${string}` = "0xcA11bde05977b3631167028862bE2a173976CA11"; 7 | export const HYPER_ACCOUNT_IMPL: `0x${string}` = "0x0000000000EDAd72076CBe7b9Cfa3751D5a85C97"; 8 | export const HYPER_ACCOUNT_UPGRADABLE_IMPL: `0x${string}` = "0x0000000000691b70A051CFAF82F9622E150369f3"; 9 | 10 | 11 | export const multicallAbi = parseAbi([ 12 | `function aggregate(Call[] calls) external payable returns (uint256 blockNumber, bytes[] returnData)`, 13 | `struct Call { address target; bytes callData; }`, 14 | ]); 15 | 16 | export const hypermapAbi = parseAbi([ 17 | "function mint(address, bytes calldata, bytes calldata, address) external returns (address tba)", 18 | "function note(bytes calldata,bytes calldata) external returns (bytes32)", 19 | "function get(bytes32 namehash) external view returns (address tokenBoundAccount, address tokenOwner, bytes memory note)", 20 | ]); 21 | 22 | export const mechAbi = parseAbi([ 23 | "function execute(address to, uint256 value, bytes calldata data, uint8 operation) returns (bytes memory returnData)", 24 | "function token() external view returns (uint256,address,uint256)" 25 | ]) 26 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/components/AppCard.tsx: -------------------------------------------------------------------------------- 1 | import { AppListing } from "../types/Apps"; 2 | import React from "react"; 3 | import { useNavigate } from "react-router-dom"; 4 | 5 | export const AppCard: React.FC<{ app: AppListing }> = ({ app }) => { 6 | if (!app || !app.package_id) return null; 7 | const navigate = useNavigate(); 8 | 9 | return ( 10 |
{ 19 | navigate(`/app/${app.package_id.package_name}:${app.package_id.publisher_node}`); 20 | }} 21 | > 22 |
23 | {`${app.metadata?.name 28 |
29 |

30 | {app.metadata?.name || app.package_id.package_name} 31 |

32 |

33 | {app.package_id.publisher_node} 34 |

35 |
36 |
37 | {app.metadata?.description && ( 38 |

39 | {app.metadata.description.length > 100 40 | ? `${app.metadata.description.substring(0, 100)}...` 41 | : app.metadata.description} 42 |

43 | )} 44 |
45 | ); 46 | }; -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link, useLocation } from 'react-router-dom'; 3 | import { STORE_PATH, PUBLISH_PATH, MY_APPS_PATH } from '../constants/path'; 4 | import { ConnectButton } from '@rainbow-me/rainbowkit'; 5 | import { FaChevronLeft } from "react-icons/fa"; 6 | import NotificationBay from './NotificationBay'; 7 | import useAppsStore from '../store'; 8 | import classNames from 'classnames'; 9 | const Header: React.FC = () => { 10 | const location = useLocation(); 11 | const { updates } = useAppsStore(); 12 | const updateCount = Object.keys(updates || {}).length; 13 | const isMobile = window.innerWidth < 768; 14 | 15 | return ( 16 |
17 |
18 | 43 |
44 |
45 | 46 | 47 |
48 |
49 | ); 50 | }; 51 | 52 | export default Header; -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/components/PackageSelector.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useMemo } from 'react'; 2 | import useAppsStore from "../store"; 3 | 4 | interface PackageSelectorProps { 5 | onPackageSelect: (packageName: string, publisherId: string) => void; 6 | publisherId: string; 7 | } 8 | 9 | const PackageSelector: React.FC = ({ onPackageSelect, publisherId }) => { 10 | const { installed, fetchInstalled } = useAppsStore(); 11 | const [selectedPackage, setSelectedPackage] = useState(""); 12 | 13 | useEffect(() => { 14 | fetchInstalled(); 15 | }, []); 16 | 17 | const filteredPackages = useMemo(() => 18 | Object.keys(installed).filter(packageFullName => 19 | packageFullName.endsWith(publisherId) 20 | ), [installed, publisherId] 21 | ); 22 | 23 | useEffect(() => { 24 | if (selectedPackage) { 25 | const packageName = selectedPackage.split(':')[0]; 26 | onPackageSelect(packageName, publisherId); 27 | } 28 | }, [selectedPackage, onPackageSelect, publisherId]); 29 | 30 | useEffect(() => { 31 | if (filteredPackages.length > 0 && !selectedPackage) { 32 | setSelectedPackage(filteredPackages[0]); 33 | } 34 | }, [filteredPackages, selectedPackage]); 35 | 36 | const handlePackageChange = (e: React.ChangeEvent) => { 37 | setSelectedPackage(e.target.value); 38 | }; 39 | 40 | return ( 41 |
42 | 59 |
60 | ); 61 | }; 62 | 63 | export default PackageSelector; -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/components/ResetButton.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { FaExclamationTriangle } from 'react-icons/fa'; 3 | import useAppsStore from '../store'; 4 | import { Tooltip } from './Tooltip'; 5 | 6 | const ResetButton: React.FC = () => { 7 | const resetStore = useAppsStore(state => state.resetStore); 8 | const [isOpen, setIsOpen] = useState(false); 9 | const [isLoading, setIsLoading] = useState(false); 10 | 11 | const handleReset = async () => { 12 | try { 13 | setIsLoading(true); 14 | await resetStore(); 15 | setIsOpen(false); 16 | } catch (error) { 17 | console.error('Reset failed:', error); 18 | alert('Failed to reset the app store. Please try again.'); 19 | } finally { 20 | setIsLoading(false); 21 | } 22 | }; 23 | 24 | return ( 25 | <> 26 | 33 | 34 | {isOpen && ( 35 |
setIsOpen(false)}> 36 |
e.stopPropagation()}> 37 | 38 |
39 | 40 |

Warning

41 |
42 | 43 |

44 | This action will re-index all apps and reset the store state. 45 | Only proceed if you know what you're doing. 46 |

47 | 48 |
49 | 55 | 62 |
63 |
64 |
65 | )} 66 | 67 | ); 68 | }; 69 | 70 | export default ResetButton; 71 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/components/Tooltip.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { FaInfo } from 'react-icons/fa6'; 3 | interface TooltipProps { 4 | content: React.ReactNode; 5 | children?: React.ReactNode; 6 | } 7 | 8 | export function Tooltip({ content, children }: TooltipProps) { 9 | const [isOpen, setIsOpen] = useState(false); 10 | return ( 11 |
12 | {children} 13 | 14 | 17 | 18 | {isOpen &&
{content}
} 19 |
20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Header } from './Header'; 2 | export { default as MirrorSelector } from './MirrorSelector'; 3 | export { default as PackageSelector } from './PackageSelector'; 4 | export { default as ManifestDisplay } from './ManifestDisplay'; 5 | export { default as NotificationBay } from './NotificationBay'; 6 | export { default as ResetButton } from './ResetButton'; -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/constants/http.ts: -------------------------------------------------------------------------------- 1 | export enum HTTP_STATUS { 2 | OK = 200, 3 | CREATED = 201, 4 | ACCEPTED = 202, 5 | NO_CONTENT = 204, 6 | MOVED_PERMANENTLY = 301, 7 | FOUND = 302, 8 | SEE_OTHER = 303, 9 | NOT_MODIFIED = 304, 10 | TEMPORARY_REDIRECT = 307, 11 | PERMANENT_REDIRECT = 308, 12 | BAD_REQUEST = 400, 13 | UNAUTHORIZED = 401, 14 | FORBIDDEN = 403, 15 | NOT_FOUND = 404, 16 | PAYLOAD_TOO_LARGE = 413, 17 | UNSUPPORTED_MEDIA_TYPE = 415, 18 | TOO_MANY_REQUESTS = 429, 19 | INTERNAL_SERVER_ERROR = 500, 20 | BAD_GATEWAY = 502, 21 | SERVICE_UNAVAILABLE = 503 22 | } 23 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/constants/path.ts: -------------------------------------------------------------------------------- 1 | export const STORE_PATH = '/'; 2 | export const PUBLISH_PATH = '/publish'; 3 | export const APP_DETAILS_PATH = '/app'; 4 | export const DOWNLOAD_PATH = '/download'; 5 | export const MY_APPS_PATH = '/my-apps'; 6 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'idna-uts46-hx' { 2 | export function toAscii(domain: string, options?: object): string; 3 | export function toUnicode(domain: string, options?: object): string; 4 | } 5 | 6 | declare module '@ensdomains/eth-ens-namehash' { 7 | export function hash(name: string): string; 8 | export function normalize(name: string): string; 9 | } 10 | 11 | declare interface ImportMeta { 12 | env: { 13 | VITE_OPTIMISM_RPC_URL: string; 14 | VITE_SEPOLIA_RPC_URL: string; 15 | BASE_URL: string; 16 | VITE_NODE_URL?: string; 17 | DEV: boolean; 18 | }; 19 | } 20 | declare interface Window { 21 | our: { 22 | node: string; 23 | process: string; 24 | }; 25 | } -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import '@rainbow-me/rainbowkit/styles.css'; 5 | 6 | import { 7 | getDefaultConfig, 8 | RainbowKitProvider, 9 | } from '@rainbow-me/rainbowkit'; 10 | import { WagmiProvider, http } from 'wagmi'; 11 | import { 12 | base, 13 | } from 'wagmi/chains'; 14 | import { 15 | QueryClientProvider, 16 | QueryClient, 17 | } from "@tanstack/react-query"; 18 | 19 | 20 | import './index.css' 21 | import 'uno.css' 22 | 23 | const config = getDefaultConfig({ 24 | appName: 'Hyperware App Store', 25 | projectId: '1307513d16d359871023f1f78ac03361', 26 | chains: [base], 27 | ssr: false, 28 | transports: { 29 | [base.id]: http(), 30 | } 31 | }); 32 | 33 | const queryClient = new QueryClient(); 34 | 35 | ReactDOM.createRoot(document.getElementById('root')!).render( 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | , 45 | ) 46 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/utils/compareVersions.ts: -------------------------------------------------------------------------------- 1 | // Helper function to compare version strings 2 | export const compareVersions = (v1: string, v2: string) => { 3 | const parts1 = v1.split('.').map(Number); 4 | const parts2 = v2.split('.').map(Number); 5 | for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { 6 | const part1 = parts1[i] || 0; 7 | const part2 = parts2[i] || 0; 8 | if (part1 > part2) return 1; 9 | if (part1 < part2) return -1; 10 | } 11 | return 0; 12 | }; -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/utils/dnsWire.ts: -------------------------------------------------------------------------------- 1 | export function toDNSWireFormat(domain: string) { 2 | const parts = domain.split('.'); 3 | const result = new Uint8Array(domain.length + parts.length); 4 | let idx = 0; 5 | 6 | for (const part of parts) { 7 | const len = part.length; 8 | result[idx] = len; // write length byte 9 | idx++; 10 | for (let j = 0; j < len; j++) { 11 | result[idx] = part.charCodeAt(j); // write ASCII bytes of the label 12 | idx++; 13 | } 14 | } 15 | // result[idx] = 0; // TODO do you need null byte at the end? 16 | 17 | return `0x${Array.from(result).map(byte => byte.toString(16).padStart(2, '0')).join('')}`; 18 | } 19 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/utils/hyperhash.ts: -------------------------------------------------------------------------------- 1 | import sha3 from 'js-sha3'; 2 | import { toUnicode } from 'idna-uts46-hx'; 3 | 4 | export const hyperhash = (inputName: string): `0x${string}` => 5 | ('0x' + normalize(inputName) 6 | .split('.') 7 | .reverse() 8 | .reduce(reducer, '00'.repeat(32))) as `0x${string}`; 9 | 10 | const reducer = (node: string, label: string): string => 11 | sha3.keccak_256(Buffer.from(node + sha3.keccak_256(label), 'hex')); 12 | 13 | export const normalize = (name: string): string => { 14 | const tilde = name.startsWith('~'); 15 | const clean = tilde ? name.slice(1) : name; 16 | const normalized = clean ? unicode(clean) : clean; 17 | return tilde ? '~' + normalized : normalized; 18 | }; 19 | 20 | const unicode = (name: string): string => 21 | toUnicode(name, { useStd3ASCII: true, transitional: false }) -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/utils/ws.ts: -------------------------------------------------------------------------------- 1 | // TODO: remove as much as possible of this.. 2 | const BASE_URL = "/main:app-store:sys/"; 3 | 4 | if (window.our) window.our.process = BASE_URL?.replace("/", ""); 5 | 6 | export const PROXY_TARGET = `${(import.meta.env.VITE_NODE_URL || `http://localhost:8080`).replace(/\/+$/, '')}${BASE_URL}`; 7 | 8 | // This env also has BASE_URL which should match the process + package name 9 | export const WEBSOCKET_URL = import.meta.env.DEV 10 | ? `${PROXY_TARGET.replace('http', 'ws')}` 11 | : undefined; 12 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | // "strict": true, 19 | // "noUnusedLocals": true, 20 | // "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": [ 24 | "../src", 25 | ], 26 | "references": [{ "path": "./tsconfig.node.json" }] 27 | } 28 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/uno.config.ts: -------------------------------------------------------------------------------- 1 | ../../../../css/uno.config.ts -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/ui/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import { nodePolyfills } from 'vite-plugin-node-polyfills' 3 | import react from '@vitejs/plugin-react' 4 | import UnoCSS from '@unocss/vite' 5 | 6 | /* 7 | If you are developing a UI outside of a Hyperware project, 8 | comment out the following 2 lines: 9 | */ 10 | import manifest from '../pkg/manifest.json' 11 | import metadata from '../metadata.json' 12 | 13 | /* 14 | IMPORTANT: 15 | This must match the process name from pkg/manifest.json + pkg/metadata.json 16 | The format is "/" + "process_name:package_name:publisher_node" 17 | */ 18 | const BASE_URL = `/main:app-store:sys`; 19 | 20 | // This is the proxy URL, it must match the node you are developing against 21 | const PROXY_URL = (process.env.VITE_NODE_URL || 'http://localhost:8080').replace(/\/$/, ''); 22 | 23 | const DEV_SERVER_PORT = 3000; // Hardcoded port for the dev server... 24 | 25 | console.log('process.env.VITE_NODE_URL', process.env.VITE_NODE_URL, PROXY_URL); 26 | 27 | const openUrl = `${PROXY_URL.replace(/:\d+$/, '')}:${DEV_SERVER_PORT}${BASE_URL}`; 28 | console.log('Server will run at:', openUrl); 29 | 30 | export default defineConfig({ 31 | plugins: [ 32 | nodePolyfills({ 33 | globals: { 34 | Buffer: true, 35 | } 36 | }), 37 | UnoCSS(), 38 | react(), 39 | ], 40 | base: BASE_URL, 41 | build: { 42 | rollupOptions: { 43 | external: ['/our.js'] 44 | } 45 | }, 46 | server: { 47 | open: openUrl, 48 | port: DEV_SERVER_PORT, 49 | proxy: { 50 | [`^${BASE_URL}/our.js`]: { 51 | target: PROXY_URL, 52 | changeOrigin: true, 53 | rewrite: (path) => { 54 | console.log('Proxying jsrequest:', path); 55 | return '/our.js'; 56 | }, 57 | }, 58 | [`^${BASE_URL}/hyperware.css`]: { 59 | target: PROXY_URL, 60 | changeOrigin: true, 61 | rewrite: (path) => { 62 | console.log('Proxying csrequest:', path); 63 | return '/hyperware.css'; 64 | }, 65 | }, 66 | }, 67 | 68 | 69 | }, 70 | }); 71 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/uninstall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "uninstall" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | anyhow = "1.0" 11 | hyperware_process_lib = "1.0.5" 12 | process_macros = "0.1" 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | wit-bindgen = "0.36.0" 16 | 17 | [lib] 18 | crate-type = ["cdylib"] 19 | 20 | [package.metadata.component] 21 | package = "hyperware:process" 22 | -------------------------------------------------------------------------------- /hyperdrive/packages/app-store/uninstall/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! uninstall:app-store:sys 2 | //! terminal script for uninstalling apps from the app store. 3 | //! 4 | //! Usage: 5 | //! uninstall:app-store:sys 6 | //! 7 | //! Arguments: 8 | //! The package ID of the app (e.g., app:publisher.os) 9 | //! 10 | use crate::hyperware::process::main::{LocalRequest, LocalResponse, UninstallResponse}; 11 | use hyperware_process_lib::{ 12 | await_next_message_body, call_init, println, Address, Message, PackageId, Request, 13 | }; 14 | 15 | wit_bindgen::generate!({ 16 | path: "target/wit", 17 | generate_unused_types: true, 18 | world: "app-store-sys-v1", 19 | additional_derives: [PartialEq, serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], 20 | }); 21 | 22 | call_init!(init); 23 | fn init(our: Address) { 24 | let Ok(body) = await_next_message_body() else { 25 | println!("uninstall: failed to get args!"); 26 | return; 27 | }; 28 | 29 | let arg = String::from_utf8(body).unwrap_or_default(); 30 | 31 | if arg.is_empty() { 32 | println!("uninstall: 1 argument required, the package id of the app"); 33 | println!("example: uninstall app:publisher.os"); 34 | return; 35 | }; 36 | 37 | let Ok(package_id) = arg.parse::() else { 38 | println!("uninstall: invalid package id, make sure to include package name and publisher"); 39 | println!("example: app_name:publisher_name"); 40 | return; 41 | }; 42 | 43 | let Ok(Ok(Message::Response { body, .. })) = 44 | Request::to((our.node(), ("main", "app-store", "sys"))) 45 | .body(LocalRequest::Uninstall( 46 | crate::hyperware::process::main::PackageId { 47 | package_name: package_id.package_name.clone(), 48 | publisher_node: package_id.publisher_node.clone(), 49 | }, 50 | )) 51 | .send_and_await_response(5) 52 | else { 53 | println!("uninstall: failed to get a response from app-store..!"); 54 | return; 55 | }; 56 | 57 | let Ok(response) = body.try_into() else { 58 | println!("uninstall: failed to parse response from app-store..!"); 59 | return; 60 | }; 61 | 62 | match response { 63 | LocalResponse::UninstallResponse(UninstallResponse::Success) => { 64 | println!("successfully uninstalled package {package_id}"); 65 | } 66 | LocalResponse::UninstallResponse(UninstallResponse::Failure) => { 67 | println!("failed to uninstall package {package_id}!"); 68 | } 69 | _ => { 70 | println!("uninstall: unexpected response from app-store..!"); 71 | return; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /hyperdrive/packages/contacts/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "contacts", 5 | "get-names", 6 | ] 7 | 8 | [profile.release] 9 | panic = "abort" 10 | opt-level = "s" 11 | lto = true 12 | -------------------------------------------------------------------------------- /hyperdrive/packages/contacts/api/contacts:sys-v0.wit: -------------------------------------------------------------------------------- 1 | interface contacts { 2 | enum capability { 3 | read-name-only, 4 | read, 5 | add, 6 | remove, 7 | } 8 | 9 | variant request { 10 | /// requires ReadNameOnly capability 11 | /// lazy-load-blob: none. 12 | get-names, 13 | /// requires Read capability 14 | /// lazy-load-blob: none. 15 | get-all-contacts, 16 | /// requires Read capability 17 | /// lazy-load-blob: none. 18 | get-contact(string), 19 | /// requires Add capability 20 | /// lazy-load-blob: none. 21 | add-contact(string), 22 | /// requires Add capability 23 | /// lazy-load-blob: none. 24 | /// tuple 25 | add-field(tuple), 26 | /// requires Remove capability 27 | /// lazy-load-blob: none. 28 | remove-contact(string), 29 | /// requires Remove capability 30 | /// lazy-load-blob: none. 31 | /// tuple 32 | remove-field(tuple), 33 | } 34 | 35 | variant response { 36 | /// lazy-load-blob: none. 37 | get-names(list), 38 | /// lazy-load-blob: required; JSON all-contacts dict in blob. 39 | get-all-contacts, 40 | /// lazy-load-blob: required; JSON contact dict in blob. 41 | get-contact, 42 | /// lazy-load-blob: none. 43 | add-contact, 44 | /// lazy-load-blob: none. 45 | add-field, 46 | /// lazy-load-blob: none. 47 | remove-contact, 48 | /// lazy-load-blob: none. 49 | remove-field, 50 | /// any failed request will receive this response 51 | /// lazy-load-blob: none. 52 | err(string), 53 | } 54 | } 55 | 56 | world contacts-sys-v0 { 57 | import contacts; 58 | include process-v1; 59 | } 60 | -------------------------------------------------------------------------------- /hyperdrive/packages/contacts/contacts/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "contacts" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | hyperware_process_lib = "1.0.5" 11 | process_macros = "0.1" 12 | serde = { version = "1.0", features = ["derive"] } 13 | serde_json = "1.0" 14 | wit-bindgen = "0.36.0" 15 | 16 | [lib] 17 | crate-type = ["cdylib"] 18 | 19 | [package.metadata.component] 20 | package = "hyperware:process" 21 | -------------------------------------------------------------------------------- /hyperdrive/packages/contacts/contacts/src/icon: -------------------------------------------------------------------------------- 1 | data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwMCIgaGVpZ2h0PSIxMDAwIiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cmVjdCB4PSIyMCIgeT0iMjAiIHdpZHRoPSI5NjAiIGhlaWdodD0iOTYwIiByeD0iNDgwIiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfMjA5MV8xMDI4MikiIGZpbGwtb3BhY2l0eT0iMC40Ii8+CjxyZWN0IHg9IjIwIiB5PSIyMCIgd2lkdGg9Ijk2MCIgaGVpZ2h0PSI5NjAiIHJ4PSI0ODAiIHN0cm9rZT0idXJsKCNwYWludDFfbGluZWFyXzIwOTFfMTAyODIpIiBzdHJva2Utd2lkdGg9IjQwIi8+CjxwYXRoIGQ9Ik01ODEuMTE2IDU4NS43ODNMNjY0LjUzOCA2NjkuMTJDNjE3LjY5OSA3MTUuNzU4IDU1Ni42MjUgNzM5IDQ5NS4yNDUgNzM5QzQzMy44NjUgNzM5IDM3Mi42MzggNzE1LjYwNSAzMjYuMTA1IDY2OS4xMkMyODAuNzk3IDYyMy44NTggMjU2IDU2My45MTcgMjU2IDUwMEMyNTYgNDM2LjA4MyAyODAuOTUgMzc2LjE0MiAzMjYuMTA1IDMzMC44OEMzNzEuMjYgMjg1LjYxOSA0MzEuMjYyIDI2MSA0OTUuMjQ1IDI2MUM1NTkuMjI3IDI2MSA2MTkuMjMgMjg1LjkyNCA2NjQuNTM4IDMzMC44OEw1ODAuOTYzIDQxNC41MjNDNTQ1LjYwNCAzODMuOTQgNTA1LjE5NCAzNzQuNzY2IDQ2MS4yNjQgMzkxLjEyN0MzOTQuOTg1IDQxNS44OTkgMzY2LjgyMSA0ODkuMjk2IDM5Ny40MzUgNTUyLjc1NEMzOTguNjU5IDU1NS4yMDEgMzk4Ljk2NSA1NTguNzE4IDM5OC4zNTMgNTYxLjMxN0MzOTUuNzUxIDU3Mi40OCAzOTIuNjg5IDU4My40OSAzODkuNzgxIDU5NC4zNDZDMzg2LjEwNyA2MDcuOTU1IDM5My45MTQgNjE1Ljc1NCA0MDcuNTM3IDYxMi4yMzdDNDE4LjU1OCA2MDkuMzMxIDQyOS41NzkgNjA2LjEyIDQ0MC42IDYwMy42NzRDNDQzLjM1NSA2MDIuOTA5IDQ0Ny4wMjkgNjAzLjIxNSA0NDkuNjMxIDYwNC40MzhDNDkwLjUgNjIzLjM5OSA1MjkuOTkxIDYyMC44IDU2Ny43OTkgNTk2LjE4MUM1NzIuNTQ0IDU5My4xMjMgNTc2LjY3NyA1ODkuNDUzIDU4MS4xMTYgNTg1Ljc4M1oiIGZpbGw9InVybCgjcGFpbnQyX2xpbmVhcl8yMDkxXzEwMjgyKSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzIwOTFfMTAyODIiIHgxPSI1MDAiIHkxPSIwIiB4Mj0iNTAwIiB5Mj0iMTAwMCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjRjM1NDIyIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1vcGFjaXR5PSIwIi8+CjwvbGluZWFyR3JhZGllbnQ+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQxX2xpbmVhcl8yMDkxXzEwMjgyIiB4MT0iNzgyLjUiIHkxPSI3My41IiB4Mj0iMTg1LjUiIHkyPSI4OTQuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjRjM1NDIyIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0E1MzEwQyIvPgo8L2xpbmVhckdyYWRpZW50Pgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50Ml9saW5lYXJfMjA5MV8xMDI4MiIgeDE9Ijc1NCIgeTE9Ijg5LjUiIHgyPSIyNTYiIHkyPSIxMDE1LjUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0YzNTQyMiIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNBNzMyMEQiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K -------------------------------------------------------------------------------- /hyperdrive/packages/contacts/get-names/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "get-names" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [dependencies] 8 | anyhow = "1.0" 9 | hyperware_process_lib = "1.0.5" 10 | process_macros = "0.1" 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1.0" 13 | wit-bindgen = "0.36.0" 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | 18 | [package.metadata.component] 19 | package = "hyperware:process" 20 | -------------------------------------------------------------------------------- /hyperdrive/packages/contacts/get-names/src/lib.rs: -------------------------------------------------------------------------------- 1 | use crate::hyperware::process::contacts; 2 | use hyperware_process_lib::{call_init, println, Address, Capability, Request}; 3 | 4 | wit_bindgen::generate!({ 5 | path: "target/wit", 6 | world: "contacts-sys-v0", 7 | generate_unused_types: true, 8 | additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], 9 | }); 10 | 11 | call_init!(init); 12 | fn init(our: Address) { 13 | let contacts_process = Address::from((our.node(), ("contacts", "contacts", "sys"))); 14 | 15 | let read_names_cap = Capability::new( 16 | &contacts_process, 17 | serde_json::to_string(&contacts::Capability::ReadNameOnly).unwrap(), 18 | ); 19 | 20 | let Ok(Ok(response)) = Request::to(&contacts_process) 21 | .body(contacts::Request::GetNames) 22 | .capabilities(vec![read_names_cap]) 23 | .send_and_await_response(5) 24 | else { 25 | println!("did not receive expected response from contacts:contacts:sys"); 26 | return; 27 | }; 28 | 29 | let Ok(contacts::Response::GetNames(names)) = response.body().try_into() else { 30 | println!("did not receive GetNames response from contacts:contacts:sys"); 31 | return; 32 | }; 33 | 34 | println!("{names:?}"); 35 | } 36 | -------------------------------------------------------------------------------- /hyperdrive/packages/contacts/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Contacts", 3 | "description": "Save and manage your contacts.", 4 | "image": "", 5 | "properties": { 6 | "package_name": "contacts", 7 | "current_version": "1.0.0", 8 | "publisher": "sys", 9 | "mirrors": [], 10 | "code_hashes": { 11 | "1.0.0": "" 12 | }, 13 | "wit_version": 1, 14 | "dependencies": [] 15 | }, 16 | "external_url": "https://hyperware.ai", 17 | "animation_url": "" 18 | } 19 | -------------------------------------------------------------------------------- /hyperdrive/packages/contacts/pkg/manifest.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "process_name": "contacts", 4 | "process_wasm_path": "/contacts.wasm", 5 | "on_exit": "Restart", 6 | "request_networking": false, 7 | "request_capabilities": [ 8 | "eth:distro:sys", 9 | "homepage:homepage:sys", 10 | "http-server:distro:sys", 11 | "vfs:distro:sys" 12 | ], 13 | "grant_capabilities": [ 14 | "eth:distro:sys", 15 | "http-server:distro:sys", 16 | "terminal:terminal:sys", 17 | { 18 | "process": "terminal:terminal:sys", 19 | "params": "ReadNameOnly" 20 | }, 21 | { 22 | "process": "terminal:terminal:sys", 23 | "params": "Read" 24 | }, 25 | { 26 | "process": "terminal:terminal:sys", 27 | "params": "Add" 28 | }, 29 | { 30 | "process": "terminal:terminal:sys", 31 | "params": "Remove" 32 | }, 33 | "vfs:distro:sys" 34 | ], 35 | "public": false 36 | } 37 | ] 38 | -------------------------------------------------------------------------------- /hyperdrive/packages/contacts/pkg/scripts.json: -------------------------------------------------------------------------------- 1 | { 2 | "get_names.wasm": { 3 | "root": false, 4 | "public": false, 5 | "request_networking": false, 6 | "request_capabilities": [ 7 | "contacts:contacts:sys", 8 | { 9 | "process": "contacts:contacts:sys", 10 | "params": "ReadNameOnly" 11 | } 12 | ], 13 | "grant_capabilities": [ 14 | "contacts:contacts:sys" 15 | ], 16 | "wit_version": 1 17 | } 18 | } -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "get-block", 5 | "hns-indexer", 6 | "reset", 7 | "node-info", 8 | "state", 9 | ] 10 | 11 | [profile.release] 12 | panic = "abort" 13 | opt-level = "s" 14 | lto = true 15 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/api/hns-indexer:sys-v0.wit: -------------------------------------------------------------------------------- 1 | interface hns-indexer { 2 | /// IndexerRequests are used to query discrete information from the indexer 3 | /// for example, if you want to know the human readable name for a namehash, 4 | /// you would send a NamehashToName request. 5 | /// If you want to know the most recent on-chain routing information for a 6 | /// human readable name, you would send a NodeInfo request. 7 | /// The block parameter specifies the recency of the data: the indexer will 8 | /// not respond until it has processed events up to the specified block. 9 | variant indexer-request { 10 | /// return the human readable name for a namehash 11 | /// returns an Option 12 | namehash-to-name(namehash-to-name-request), 13 | /// return the most recent on-chain routing information for a node name. 14 | /// returns an Option 15 | /// set block to 0 if you just want to get the current state of the indexer 16 | node-info(node-info-request), 17 | /// return the entire state of the indexer at the given block 18 | /// set block to 0 if you just want to get the current state of the indexer 19 | get-state(get-state-request), 20 | /// resets and re-indexes the chain, requires root cap, 21 | /// returns a response varaint reset 22 | reset, 23 | } 24 | 25 | variant indexer-response { 26 | name(option), 27 | node-info(option), 28 | get-state(wit-state), 29 | reset(reset-result), 30 | } 31 | 32 | record namehash-to-name-request { 33 | hash: string, 34 | block: u64, 35 | } 36 | 37 | record node-info-request { 38 | name: string, 39 | block: u64, 40 | } 41 | 42 | record wit-hns-update { 43 | name: string, 44 | public-key: string, 45 | ips: list, 46 | ports: list>, // map, but wit doesn't support maps 47 | routers: list, 48 | } 49 | 50 | record get-state-request { 51 | block: u64, 52 | } 53 | 54 | record wit-state { 55 | chain-id: u64, 56 | contract-address: list, // 20-byte ETH address 57 | names: list>, // map, but wit doesn't support maps 58 | nodes: list>, // map, but wit doesn't support maps 59 | last-block: u64, 60 | } 61 | 62 | variant reset-result { 63 | success, 64 | err(reset-error), 65 | } 66 | 67 | variant reset-error { 68 | no-root-cap, 69 | db-error(string), 70 | } 71 | } 72 | 73 | world hns-indexer-sys-v0 { 74 | import hns-indexer; 75 | include process-v1; 76 | } 77 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/get-block/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "get_block" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | hyperware_process_lib = "1.0.5" 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1.0" 13 | wit-bindgen = "0.36.0" 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | 18 | [package.metadata.component] 19 | package = "hyperware:process" 20 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/get-block/src/lib.rs: -------------------------------------------------------------------------------- 1 | use hyperware_process_lib::{eth, script, Address}; 2 | 3 | wit_bindgen::generate!({ 4 | path: "target/wit", 5 | world: "process-v1", 6 | }); 7 | 8 | script!(init); 9 | fn init(_our: Address, args: String) -> String { 10 | // call get_block with the chain id provided in the args 11 | let chain_id = args 12 | .split_whitespace() 13 | .next() 14 | .unwrap_or("1") 15 | .parse::() 16 | .unwrap_or(1); 17 | 18 | // request timeout of 5s 19 | let provider = eth::Provider::new(chain_id, 5); 20 | 21 | match provider.get_block_number() { 22 | Ok(block_number) => format!("latest block number: {block_number}"), 23 | Err(e) => format!("failed to get block number: {e:?}"), 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/hns-indexer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hns-indexer" 3 | version = "0.2.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | anyhow = "1.0" 11 | alloy-primitives = "0.8.15" 12 | alloy-sol-types = "0.8.15" 13 | hex = "0.4.3" 14 | hyperware_process_lib = "1.0.5" 15 | process_macros = "0.1" 16 | rmp-serde = "1.1.2" 17 | serde = { version = "1.0", features = ["derive"] } 18 | serde_json = "1.0" 19 | thiserror = "1.0" 20 | wit-bindgen = "0.36.0" 21 | 22 | [lib] 23 | crate-type = ["cdylib"] 24 | 25 | [package.metadata.component] 26 | package = "hyperware:process" 27 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "HNS Indexer", 3 | "description": "Hyperware PKI indexer", 4 | "image": "", 5 | "properties": { 6 | "package_name": "hns-indexer", 7 | "current_version": "1.0.0", 8 | "publisher": "sys", 9 | "mirrors": [], 10 | "code_hashes": { 11 | "1.0.0": "" 12 | }, 13 | "wit_version": 1, 14 | "dependencies": [] 15 | }, 16 | "external_url": "https://hyperware.ai", 17 | "animation_url": "" 18 | } 19 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/node-info/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "node_info" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | hyperware_process_lib = "1.0.5" 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1.0" 13 | process_macros = "0.1" 14 | wit-bindgen = "0.36.0" 15 | 16 | [lib] 17 | crate-type = ["cdylib"] 18 | 19 | [package.metadata.component] 20 | package = "hyperware:process" 21 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/node-info/src/lib.rs: -------------------------------------------------------------------------------- 1 | use hyperware::process::hns_indexer::{IndexerRequest, IndexerResponse, NodeInfoRequest}; 2 | use hyperware_process_lib::{println, script, Address, Request}; 3 | use std::str::FromStr; 4 | 5 | wit_bindgen::generate!({ 6 | path: "target/wit", 7 | world: "hns-indexer-sys-v0", 8 | generate_unused_types: true, 9 | additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], 10 | }); 11 | 12 | script!(init); 13 | fn init(_our: Address, args: String) -> String { 14 | let node_name = args.split_whitespace().next().unwrap_or("").to_string(); 15 | 16 | let hns = Address::from_str("our@hns-indexer:hns-indexer:sys").unwrap(); 17 | 18 | let resp = Request::to(hns) 19 | .body(IndexerRequest::NodeInfo(NodeInfoRequest { 20 | name: node_name, 21 | block: 0, 22 | })) 23 | .send_and_await_response(5) 24 | .unwrap() 25 | .unwrap(); 26 | 27 | let resp = serde_json::from_slice::(&resp.body()).unwrap(); 28 | 29 | match resp { 30 | IndexerResponse::NodeInfo(node_info) => { 31 | format!("node info: {node_info:#?}") 32 | } 33 | _ => "node info: name not found".to_string(), 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/pkg/manifest.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "process_name": "hns-indexer", 4 | "process_wasm_path": "/hns-indexer.wasm", 5 | "on_exit": "Restart", 6 | "request_networking": false, 7 | "request_capabilities": [ 8 | "eth:distro:sys", 9 | "http-server:distro:sys", 10 | "net:distro:sys", 11 | "timer:distro:sys", 12 | "kv:distro:sys" 13 | ], 14 | "grant_capabilities": [ 15 | "eth:distro:sys", 16 | "http-server:distro:sys", 17 | "timer:distro:sys", 18 | "kv:distro:sys" 19 | ], 20 | "public": false 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/pkg/scripts.json: -------------------------------------------------------------------------------- 1 | { 2 | "get-block.wasm": { 3 | "root": false, 4 | "public": false, 5 | "request_networking": false, 6 | "request_capabilities": [ 7 | "eth:distro:sys" 8 | ], 9 | "grant_capabilities": [ 10 | "eth:distro:sys" 11 | ], 12 | "wit_version": 1 13 | }, 14 | "reset.wasm": { 15 | "root": false, 16 | "public": false, 17 | "request_networking": false, 18 | "request_capabilities": [ 19 | "hns-indexer:hns-indexer:sys", 20 | { 21 | "process": "hns-indexer:hns-indexer:sys", 22 | "params": { 23 | "root": true 24 | } 25 | } 26 | ], 27 | "grant_capabilities": [ 28 | "hns-indexer:hns-indexer:sys" 29 | ], 30 | "wit_version": 1 31 | }, 32 | "node-info.wasm": { 33 | "root": false, 34 | "public": false, 35 | "request_networking": false, 36 | "request_capabilities": [ 37 | "hns-indexer:hns-indexer:sys" 38 | ], 39 | "grant_capabilities": [ 40 | "hns-indexer:hns-indexer:sys" 41 | ], 42 | "wit_version": 1 43 | }, 44 | "state.wasm": { 45 | "root": false, 46 | "public": false, 47 | "request_networking": false, 48 | "request_capabilities": [ 49 | "hns-indexer:hns-indexer:sys" 50 | ], 51 | "grant_capabilities": [ 52 | "hns-indexer:hns-indexer:sys" 53 | ], 54 | "wit_version": 1 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/reset/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "reset" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | hyperware_process_lib = "1.0.5" 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1.0" 13 | process_macros = "0.1" 14 | wit-bindgen = "0.36.0" 15 | 16 | [lib] 17 | crate-type = ["cdylib"] 18 | 19 | [package.metadata.component] 20 | package = "hyperware:process" 21 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/reset/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | use hyperware::process::hns_indexer::IndexerRequest; 4 | use hyperware_process_lib::{call_init, Address, Request}; 5 | 6 | wit_bindgen::generate!({ 7 | path: "target/wit", 8 | world: "hns-indexer-sys-v0", 9 | generate_unused_types: true, 10 | additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], 11 | }); 12 | 13 | call_init!(init); 14 | fn init(_our: Address) { 15 | // request timeout of 5s 16 | let hns = Address::from_str("our@hns-indexer:hns-indexer:sys").unwrap(); 17 | 18 | let _resp = Request::to(hns) 19 | .body(IndexerRequest::Reset) 20 | .send_and_await_response(5) 21 | .unwrap() 22 | .unwrap(); 23 | } 24 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/state/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "state" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | hyperware_process_lib = "1.0.5" 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1.0" 13 | process_macros = "0.1" 14 | wit-bindgen = "0.36.0" 15 | 16 | [lib] 17 | crate-type = ["cdylib"] 18 | 19 | [package.metadata.component] 20 | package = "hyperware:process" 21 | -------------------------------------------------------------------------------- /hyperdrive/packages/hns-indexer/state/src/lib.rs: -------------------------------------------------------------------------------- 1 | use crate::hyperware::process::hns_indexer::{GetStateRequest, IndexerRequest, IndexerResponse}; 2 | use hyperware_process_lib::{eth, script, Address, Message, Request}; 3 | 4 | wit_bindgen::generate!({ 5 | path: "target/wit", 6 | world: "hns-indexer-sys-v0", 7 | generate_unused_types: true, 8 | additional_derives: [serde::Deserialize, serde::Serialize, process_macros::SerdeJsonInto], 9 | }); 10 | 11 | script!(init); 12 | fn init(_our: Address, _args: String) -> String { 13 | // we don't take any args 14 | 15 | let Ok(Message::Response { body, .. }) = 16 | Request::to(("our", "hns-indexer", "hns-indexer", "sys")) 17 | .body(IndexerRequest::GetState(GetStateRequest { block: 0 })) 18 | .send_and_await_response(10) 19 | .unwrap() 20 | else { 21 | return "failed to get state from hns-indexer".to_string(); 22 | }; 23 | let Ok(IndexerResponse::GetState(state)) = body.try_into() else { 24 | return "failed to deserialize state".to_string(); 25 | }; 26 | // can change later, but for now, just print every known node name 27 | let mut names = state 28 | .names 29 | .iter() 30 | .map(|(_k, v)| v.clone()) 31 | .collect::>(); 32 | names.sort(); 33 | let contract_address: [u8; 20] = state 34 | .contract_address 35 | .try_into() 36 | .expect("invalid contract addess: doesn't have 20 bytes"); 37 | let contract_address: eth::Address = contract_address.into(); 38 | format!( 39 | "\nrunning on chain id {}\nCA: {}\n{} known nodes as of block {}\n {}", 40 | state.chain_id, 41 | contract_address, 42 | names.len(), 43 | state.last_block, 44 | names.join("\n ") 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "homepage", 5 | ] 6 | 7 | [profile.release] 8 | panic = "abort" 9 | opt-level = "s" 10 | lto = true 11 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/api/homepage:sys-v1.wit: -------------------------------------------------------------------------------- 1 | interface homepage { 2 | enum capability { 3 | remove-other, 4 | set-stylesheet, 5 | } 6 | 7 | /// The request format to add or remove an app from the homepage. You must have messaging 8 | /// access to `homepage:homepage:sys` in order to perform this. Serialize using serde_json. 9 | variant request { 10 | /// the package and process name will come from request source. 11 | /// the path will automatically have the process_id prepended. 12 | /// the icon is a base64 encoded image. 13 | /// 14 | /// lazy-load-blob: none. 15 | add(add-request), 16 | /// remove ourself from homepage (message source will be item removed) 17 | /// 18 | /// lazy-load-blob: none. 19 | remove, 20 | /// remove another app from homepage 21 | /// using this requires RemoveOther capability 22 | /// app store uses this to remove apps on uninstall 23 | /// 24 | /// lazy-load-blob: none. 25 | remove-other(string), 26 | /// set the stylesheet for the homepage 27 | /// using this requires SetStylesheet capability 28 | /// settings:settings:sys uses this to set the stylesheet 29 | /// 30 | /// lazy-load-blob: none. 31 | set-stylesheet(string), 32 | /// get the list of apps currently on the homepage 33 | /// 34 | /// lazy-load-blob: none. 35 | get-apps, 36 | } 37 | 38 | /// The response format to get from the homepage. Serialized using serde_json. 39 | variant response { 40 | get-apps(list), 41 | } 42 | 43 | record add-request { 44 | label: string, 45 | icon: option, 46 | path: option, 47 | widget: option, 48 | } 49 | 50 | record app { 51 | id: string, 52 | process: string, 53 | package-name: string, 54 | publisher: string, 55 | path: option, 56 | label: string, 57 | base64-icon: option, 58 | widget: option, 59 | order: u32, 60 | favorite: bool, 61 | } 62 | } 63 | 64 | world homepage-sys-v1 { 65 | import homepage; 66 | include process-v1; 67 | } 68 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/homepage/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "homepage" 3 | version = "0.1.2" 4 | edition = "2021" 5 | 6 | [features] 7 | simulation-mode = [] 8 | 9 | [dependencies] 10 | anyhow = "1.0" 11 | bincode = "1.3.3" 12 | hyperware_process_lib = "1.0.5" 13 | serde = { version = "1.0", features = ["derive"] } 14 | serde_json = "1.0" 15 | wit-bindgen = "0.36.0" 16 | 17 | [lib] 18 | crate-type = ["cdylib"] 19 | 20 | [package.metadata.component] 21 | package = "hyperware:process" 22 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Homepage", 3 | "description": "Homepage for Hyperware", 4 | "image": "", 5 | "properties": { 6 | "package_name": "homepage", 7 | "current_version": "1.0.0", 8 | "publisher": "sys", 9 | "mirrors": [], 10 | "code_hashes": { 11 | "1.0.0": "" 12 | }, 13 | "wit_version": 1, 14 | "dependencies": [] 15 | }, 16 | "external_url": "https://hyperware.ai", 17 | "animation_url": "" 18 | } 19 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/pkg/h-plain.svg: -------------------------------------------------------------------------------- 1 | 2 | 11 | 13 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/pkg/hyperware.css: -------------------------------------------------------------------------------- 1 | ../../../../css/hyperware.css -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/pkg/hyperware.svg: -------------------------------------------------------------------------------- 1 | ../../../../css/hyperware.svg -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/pkg/manifest.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "process_name": "homepage", 4 | "process_wasm_path": "/homepage.wasm", 5 | "on_exit": "Restart", 6 | "request_networking": false, 7 | "request_capabilities": [ 8 | "http-server:distro:sys", 9 | "vfs:distro:sys" 10 | ], 11 | "grant_capabilities": [ 12 | "http-server:distro:sys" 13 | ], 14 | "public": false 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/ui/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | ignorePatterns: ['dist', '.eslintrc.cjs'], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': [ 14 | 'warn', 15 | { allowConstantExport: true }, 16 | ], 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/ui/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/ui/README.md: -------------------------------------------------------------------------------- 1 | # Hyperware Homepage UI 2 | 3 | The homepage for Hyperware. 4 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/ui/build.sh: -------------------------------------------------------------------------------- 1 | npm install && npm run build:copy -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 33 | 34 | 36 | 37 | 38 | 39 | 40 |
41 | 42 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperware-homepage-ui", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "build:copy": "npm run build && rm -rf ../pkg/ui && cp -r dist ../pkg/ui && rm -rf dist", 10 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 11 | "preview": "vite preview" 12 | }, 13 | "dependencies": { 14 | "@hello-pangea/dnd": "^16.6.0", 15 | "classnames": "^2.5.1", 16 | "react": "^18.2.0", 17 | "react-beautiful-dnd": "^13.1.1", 18 | "react-dom": "^18.2.0", 19 | "react-icons": "^5.1.0", 20 | "react-router-dom": "^6.23.0", 21 | "unocss": "^0.59.4", 22 | "zustand": "^4.5.2" 23 | }, 24 | "devDependencies": { 25 | "@types/node": "^20.10.4", 26 | "@types/react": "^18.2.66", 27 | "@types/react-beautiful-dnd": "^13.1.8", 28 | "@types/react-dom": "^18.2.22", 29 | "@typescript-eslint/eslint-plugin": "^7.2.0", 30 | "@typescript-eslint/parser": "^7.2.0", 31 | "@vitejs/plugin-react": "^4.2.1", 32 | "esbuild": ">0.24.2", 33 | "eslint": "^8.57.0", 34 | "eslint-plugin-react-hooks": "^4.6.0", 35 | "eslint-plugin-react-refresh": "^0.4.6", 36 | "rollup": "^4.35.0", 37 | "typescript": "^5.2.2", 38 | "vite": "^5.2.0" 39 | }, 40 | "optionalDependencies": { 41 | "@rollup/rollup-android-arm-eabi": "^4.35.0", 42 | "@rollup/rollup-android-arm64": "^4.35.0", 43 | "@rollup/rollup-darwin-arm64": "^4.35.0", 44 | "@rollup/rollup-darwin-x64": "^4.35.0", 45 | "@rollup/rollup-freebsd-arm64": "^4.35.0", 46 | "@rollup/rollup-freebsd-x64": "^4.35.0", 47 | "@rollup/rollup-linux-arm-gnueabihf": "^4.35.0", 48 | "@rollup/rollup-linux-arm-musleabihf": "^4.35.0", 49 | "@rollup/rollup-linux-arm64-gnu": "^4.35.0", 50 | "@rollup/rollup-linux-arm64-musl": "^4.35.0", 51 | "@rollup/rollup-linux-loongarch64-gnu": "^4.35.0", 52 | "@rollup/rollup-linux-powerpc64le-gnu": "^4.35.0", 53 | "@rollup/rollup-linux-riscv64-gnu": "^4.35.0", 54 | "@rollup/rollup-linux-s390x-gnu": "^4.35.0", 55 | "@rollup/rollup-linux-x64-gnu": "^4.35.0", 56 | "@rollup/rollup-linux-x64-musl": "^4.35.0", 57 | "@rollup/rollup-win32-arm64-msvc": "^4.35.0", 58 | "@rollup/rollup-win32-ia32-msvc": "^4.35.0", 59 | "@rollup/rollup-win32-x64-msvc": "^4.35.0" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/ui/src/components/AppDisplay.tsx: -------------------------------------------------------------------------------- 1 | import { HomepageApp } from "../store/homepageStore"; 2 | 3 | interface AppDisplayProps { 4 | app?: HomepageApp; 5 | } 6 | 7 | const AppDisplay: React.FC = ({ app }) => { 8 | return ( 9 | 27 | {app?.base64_icon ? ( 28 | 29 | ) : ( 30 | 31 | )} 32 |
{app?.label || app?.package_name}
33 |
34 | ); 35 | }; 36 | 37 | export default AppDisplay; 38 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/ui/src/components/HyperwareLogo.tsx: -------------------------------------------------------------------------------- 1 | import type { SVGProps } from "react"; 2 | // 3 | // 15 | // 16 | const SvgHyperwareSmall = (props: SVGProps) => { 17 | const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; 18 | const fillStyle = isDark ? '#dcff71' : '#004fff'; 19 | 20 | return ( 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ); 42 | }; 43 | 44 | export default SvgHyperwareSmall; 45 | 46 | -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/ui/src/components/Modal.tsx: -------------------------------------------------------------------------------- 1 | import { FaX } from "react-icons/fa6" 2 | import { useEffect } from 'react'; 3 | import classNames from "classnames"; 4 | 5 | interface Props extends React.HTMLAttributes { 6 | title: string 7 | onClose: () => void 8 | outerClassName?: string 9 | innerClassName?: string 10 | } 11 | 12 | export const Modal: React.FC = ({ title, onClose, children, outerClassName, innerClassName }) => { 13 | useEffect(() => { 14 | const handleKeyDown = (event: KeyboardEvent) => { 15 | if (event.key === 'Escape') { 16 | onClose(); 17 | } 18 | }; 19 | 20 | window.addEventListener('keydown', handleKeyDown); 21 | 22 | return () => { 23 | window.removeEventListener('keydown', handleKeyDown); 24 | }; 25 | }, [onClose]); 26 | 27 | return ( 28 |
36 |
46 |
47 |

{title}

48 | 54 |
55 | {children} 56 |
57 |
58 | ) 59 | } -------------------------------------------------------------------------------- /hyperdrive/packages/homepage/ui/src/components/Widget.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react" 2 | import usePersistentStore from "../store/persistentStore" 3 | 4 | interface WidgetProps { 5 | id: string 6 | label: string 7 | widget: string 8 | } 9 | 10 | const Widget: React.FC = ({ id, label, widget }) => { 11 | const [_tallScreen, setTallScreen] = useState(window.innerHeight > window.innerWidth) 12 | const { toggleWidgetVisibility } = usePersistentStore(); 13 | 14 | useEffect(() => { 15 | setTallScreen(window.innerHeight > window.innerWidth) 16 | }, [window.innerHeight, window.innerWidth]) 17 | 18 | useEffect(() => { 19 | const hideWidget = () => { 20 | toggleWidgetVisibility(id) 21 | } 22 | document.getElementById(`hide-widget-${id}`)?.addEventListener("click", hideWidget) 23 | }, []) 24 | 25 | return
26 |

{label}

[hide]

27 |