├── .github
├── dependabot.yml
├── pull_request_template.md
└── workflows
│ ├── ci.yml
│ ├── generated-pr.yml
│ ├── semantic-pull-request.yml
│ └── stale.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── examples
├── js-libp2p-example-auto-tls
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── auto-confirm.js
│ ├── package.json
│ └── trust-free.js
├── js-libp2p-example-browser-pubsub
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── index.html
│ ├── index.js
│ ├── package.json
│ ├── relay.js
│ ├── test
│ │ └── index.spec.js
│ └── vite.config.js
├── js-libp2p-example-chat
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ ├── dialer.js
│ │ ├── libp2p.js
│ │ ├── listener.js
│ │ └── stream.js
│ └── test
│ │ └── index.spec.js
├── js-libp2p-example-circuit-relay
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── dialer.js
│ ├── listener.js
│ ├── package.json
│ ├── relay.js
│ └── test
│ │ └── index.spec.js
├── js-libp2p-example-connection-encryption
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── noise.js
│ ├── package.json
│ ├── plaintext.js
│ └── test
│ │ └── index.spec.js
├── js-libp2p-example-custom-protocols
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── 1-echo.js
│ ├── 2-request-response.js
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── package.json
│ └── test
│ │ ├── 1-echo.spec.js
│ │ └── 2-request-response.spec.js
├── js-libp2p-example-delegated-routing
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── package.json
│ ├── server.js
│ ├── src
│ │ ├── App.js
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── libp2p.js
│ │ └── main.css
│ ├── test
│ │ └── index.spec.js
│ └── vite.config.js
├── js-libp2p-example-discovery-mechanisms
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── 1-dht.js
│ ├── 2-mdns.js
│ ├── 3-pubsub.js
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── bootstrappers.js
│ ├── package.json
│ └── test
│ │ ├── test-1-dht.spec.js
│ │ ├── test-2-mdns.spec.js
│ │ └── test-3-pubsub.spec.js
├── js-libp2p-example-peer-and-content-routing
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── 1.js
│ ├── 2.js
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── package.json
│ └── test
│ │ ├── index.js
│ │ ├── test-1.js
│ │ └── test-2.js
├── js-libp2p-example-pnet
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── index.js
│ ├── libp2p-node.js
│ ├── package.json
│ └── test
│ │ └── index.js
├── js-libp2p-example-protocol-and-stream-muxing
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── 1.js
│ ├── 2.js
│ ├── 3.js
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── package.json
│ └── test
│ │ ├── test-1.js
│ │ ├── test-2.js
│ │ ├── test-3.js
│ │ └── test.js
├── js-libp2p-example-pubsub
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── 1.js
│ ├── 2.js
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── package.json
│ └── test
│ │ ├── test-1.js
│ │ ├── test-2.js
│ │ └── test.js
├── js-libp2p-example-transports
│ ├── .github
│ │ ├── pull_request_template.md
│ │ └── workflows
│ │ │ └── sync.yml
│ ├── 1.js
│ ├── 2.js
│ ├── 3.js
│ ├── 4.js
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── package.json
│ ├── test
│ │ ├── test-1.js
│ │ ├── test-2.js
│ │ ├── test-3.js
│ │ ├── test-4.js
│ │ └── test.js
│ └── test_certs
│ │ ├── cert.pem
│ │ └── key.pem
└── js-libp2p-example-webrtc-private-to-private
│ ├── .github
│ ├── pull_request_template.md
│ └── workflows
│ │ └── sync.yml
│ ├── LICENSE
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ ├── index.html
│ ├── index.js
│ ├── package.json
│ ├── relay.js
│ ├── test
│ └── index.spec.js
│ └── vite.config.js
└── package.json
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: npm
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | time: "11:00"
8 | open-pull-requests-limit: 50
9 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Title
2 |
8 |
9 | ## Description
10 |
11 |
17 |
18 | ## Notes & open questions
19 |
20 |
23 |
24 | ## Change checklist
25 |
26 | - [ ] I have performed a self-review of my own code
27 | - [ ] I have made corresponding changes to the documentation if necessary (this includes comments as well)
28 | - [ ] I have added tests that prove my fix is effective or that my feature works
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - '**'
10 |
11 | concurrency:
12 | group: ${{ github.head_ref || github.ref_name }}
13 | cancel-in-progress: true
14 |
15 | jobs:
16 | examples:
17 | runs-on: ubuntu-latest
18 | name: Test ${{ matrix.project }}
19 | strategy:
20 | fail-fast: false
21 | matrix:
22 | project:
23 | - js-libp2p-example-auto-tls
24 | - js-libp2p-example-browser-pubsub
25 | - js-libp2p-example-chat
26 | - js-libp2p-example-circuit-relay
27 | - js-libp2p-example-connection-encryption
28 | - js-libp2p-example-custom-protocols
29 | - js-libp2p-example-delegated-routing
30 | - js-libp2p-example-discovery-mechanisms
31 | - js-libp2p-example-peer-and-content-routing
32 | - js-libp2p-example-pnet
33 | - js-libp2p-example-protocol-and-stream-muxing
34 | - js-libp2p-example-pubsub
35 | - js-libp2p-example-transports
36 | - js-libp2p-example-webrtc-private-to-private
37 | defaults:
38 | run:
39 | working-directory: examples/${{ matrix.project }}
40 | steps:
41 | - uses: actions/checkout@v3
42 | - uses: actions/setup-node@v3
43 | with:
44 | node-version: lts/*
45 | - name: Install dependencies
46 | run: npm install
47 | - name: Install Playwright
48 | run: npx -y playwright install --with-deps
49 | - name: Run tests
50 | run: npm run test
51 | env:
52 | CI: true
53 |
54 | monorepo:
55 | runs-on: ubuntu-latest
56 | name: Test monorepo
57 | steps:
58 | - uses: actions/checkout@v3
59 | - uses: actions/setup-node@v3
60 | with:
61 | node-version: lts/*
62 | - name: Install dependencies
63 | run: npm install
64 | - name: Install Playwright
65 | run: npx -y playwright install --with-deps
66 | - name: Run linting
67 | run: npm run lint
68 | env:
69 | CI: true
70 | - name: Run tests
71 | run: npm run test
72 | env:
73 | CI: true
74 |
75 | push-changes:
76 | name: Push changes
77 | runs-on: ubuntu-latest
78 | needs: [monorepo, examples]
79 | if: github.event_name == 'push' && github.ref == 'refs/heads/main'
80 | strategy:
81 | fail-fast: true
82 | matrix:
83 | project:
84 | - js-libp2p-example-auto-tls
85 | - js-libp2p-example-browser-pubsub
86 | - js-libp2p-example-chat
87 | - js-libp2p-example-circuit-relay
88 | - js-libp2p-example-connection-encryption
89 | - js-libp2p-example-custom-protocols
90 | - js-libp2p-example-delegated-routing
91 | - js-libp2p-example-discovery-mechanisms
92 | - js-libp2p-example-peer-and-content-routing
93 | - js-libp2p-example-pnet
94 | - js-libp2p-example-protocol-and-stream-muxing
95 | - js-libp2p-example-pubsub
96 | - js-libp2p-example-transports
97 | - js-libp2p-example-webrtc-private-to-private
98 | steps:
99 | - uses: convictional/trigger-workflow-and-wait@f69fa9eedd3c62a599220f4d5745230e237904be
100 | with:
101 | owner: libp2p
102 | repo: ${{ matrix.project }}
103 | github_token: ${{ secrets.REPO_PULL_TOKEN }}
104 | workflow_file_name: sync.yml
105 |
--------------------------------------------------------------------------------
/.github/workflows/generated-pr.yml:
--------------------------------------------------------------------------------
1 | name: Close Generated PRs
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * *'
6 | workflow_dispatch:
7 |
8 | permissions:
9 | issues: write
10 | pull-requests: write
11 |
12 | jobs:
13 | stale:
14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-generated-pr.yml@v1
15 |
--------------------------------------------------------------------------------
/.github/workflows/semantic-pull-request.yml:
--------------------------------------------------------------------------------
1 | name: Semantic PR
2 |
3 | on:
4 | pull_request_target:
5 | types:
6 | - opened
7 | - edited
8 | - synchronize
9 |
10 | jobs:
11 | main:
12 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-semantic-pull-request.yml@v1
13 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: Close Stale Issues
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * *'
6 | workflow_dispatch:
7 |
8 | permissions:
9 | issues: write
10 | pull-requests: write
11 |
12 | jobs:
13 | stale:
14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-stale-issue.yml@v1
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 | dist
4 | .docs
5 | .coverage
6 | node_modules
7 | package-lock.json
8 | yarn.lock
9 | .DS_Store
10 | .next
11 | .vscode
12 | test-results
13 | playwright-report
14 | .parcel-cache
15 | .envrc
16 | .tool-versions
17 | db
18 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
4 |
5 | ## Table of Contents
6 |
7 | - [Howto](#howto)
8 | - [How to add a new example](#how-to-add-a-new-example)
9 | - [Examples must](#examples-must)
10 | - [Update `js-libp2p` to run tests against the repo](#update-js-libp2p-to-run-tests-against-the-repo)
11 |
12 |
13 | ## Howto
14 |
15 | 1. Fork the IPFS Examples Project (`https://github.com/libp2p/js-libp2p-examples`)
16 | 2. Create your Feature Branch (`git checkout -b feature/amazing-feature`)
17 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing feature'`)
18 | 4. Push to the Branch (`git push origin feature/amazing-feature`)
19 | 5. Open a Pull Request
20 |
21 | ## How to add a new example
22 |
23 | 1. Decide on a pithy folder name for your example, it should start with `js-libp2p-example-` and ideally be one or two words that describe what it's about - e.g. `js-libp2p-example-transfer-files`
24 | 1. Create a folder in this repo under `examples`, eg. `./examples/js-libp2p-example-transfer-files`
25 | 1. Add the files and tests that make up the example
26 | 1. Add the folder name to the `project-list` lists in the `examples` and `push-changes` jobs in this repositories `./github/ci.yml`
27 | 1. Create a PR to https://github.com/libp2p/github-mgmt similar to https://github.com/libp2p/github-mgmt/pull/22 to facilitate the addition of your project as an isolated repo.
28 |
29 | ## Examples must
30 |
31 | - Live inside the `/examples/` folder
32 | - Have tests and should make use of `test-ipfs-example` library
33 | - Implement the following scripts:
34 | - `clean`: used to clean all the unnecessary code (e.g.: files generated by bundlers and package managers)
35 | - `build`: used to build the example
36 | - `start`: used to start the example
37 | - `test`: used to test the example
38 | - The `README.md` must have (see example inside `example-template`):
39 | - Link to `Codesandbox.com` for one-click running demonstration
40 | - References for documentation/tutorials used to build the example
41 | - _Optional:_ Screenshots, gifs, etc... under `img/` folder
42 | - Update the CI to run the tests of the new example as standalone
43 | - Edit `github/workflows/ci.yml`
44 | - Add the test name to `project` under `matrix`
45 |
46 | ## Update `js-libp2p` to run tests against the repo
47 |
48 | Open a PR to the [libp2p/js-libp2p](https://github.com/libp2p/js-libp2p) project that edits the `.github/workflows/examples.yml` in order to make sure a libp2p release does not break your new example.
49 |
50 | Search `.github/workflows/test.yml` for the `test-examples` section and add a block at the end of the `example` matrix key similar to:
51 |
52 | ```yml
53 | - name: my super fun new example
54 | repo: https://github.com/libp2p/js-libp2p-my-super-fun-new-example.git
55 | deps: libp2p@$PWD/packages/libp2p/dist
56 | ```
57 |
58 | The value of the `deps` key will vary depending on which modules from Helia your example uses. Above we override the `helia` module, but your example may different deps.
59 |
60 | Please see the existing setup in `.github/workflows/test.yml` for how to ensure you are overriding the correct modules.
61 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | A collection of js-libp2p examples
8 |
9 |
10 |
11 |
12 | Explore the docs
13 | ·
14 | Report Bug
15 | ·
16 | Request Feature/Example
17 |
18 |
19 | ## Table of Contents
20 |
21 | - [About The Project](#about-the-project)
22 | - [Getting Started](#getting-started)
23 | - [Prerequisites](#prerequisites)
24 | - [Understanding how libp2p works](#understanding-how-libp2p-works)
25 | - [Other examples](#other-examples)
26 | - [Contribute](#contribute)
27 | - [License](#license)
28 |
29 | ## About The Project
30 |
31 | - Read the [js-libp2p documentation](https://github.com/libp2p/js-libp2p/tree/main/doc)
32 | - Check out the [js-libp2p API docs](https://libp2p.github.io/js-libp2p/)
33 | - Check out the [general libp2p documentation](https://docs.libp2p.io) for tips, how-tos and more
34 | - Read the [libp2p specs](https://github.com/libp2p/specs)
35 | - See https://blog.libp2p.io for news and more
36 | - Head over to https://proto.school to take interactive tutorials that cover core libp2p APIs
37 | - Need help? Visit the discussion board: https://github.com/libp2p/js-libp2p/discussions
38 |
39 | ## Getting Started
40 |
41 | Feel free to jump directly into the examples, however going through the following sections will help build context and background knowledge.
42 |
43 | ### Prerequisites
44 |
45 | Make sure you have installed all of the following prerequisites on your development machine:
46 |
47 | - Git - [Download & Install Git](https://git-scm.com/downloads). OSX and Linux machines typically have this already installed.
48 | - Node.js - [Download & Install Node.js](https://nodejs.org/en/download/) and the npm package manager.
49 |
50 | ### Understanding how libp2p works
51 |
52 | - [Circuit Relay](https://github.com/libp2p/js-libp2p-example-circuit-relay) - configuring Circuit Relay connections
53 | - [Connection Encryption](https://github.com/libp2p/js-libp2p-example-connection-encryption) - how to encrypt connection between libp2p nodes
54 | - [Delegated routing](https://github.com/libp2p/js-libp2p-example-delegated-routing) - how to offload network operations and queries onto more capable nodes
55 | - [Discovery mechanisms](https://github.com/libp2p/js-libp2p-example-discovery-mechanisms) - how libp2p discovers other peers on the network
56 | - [Custom protocols](https://github.com/libp2p/js-libp2p-example-custom-protocols) - how to create a custom protocol for your application
57 | - [Transports](https://github.com/libp2p/js-libp2p-example-transports) - how to connect peers together via different transports
58 | - [WebRTC](https://github.com/libp2p/js-libp2p-example-webrtc-private-to-private) - a special transport for connecting browsers together
59 |
60 | ### Other examples
61 |
62 | These are demo apps or examples that showcase specific modules or services:
63 |
64 | - [Chat](https://github.com/libp2p/js-libp2p-example-chat) - a simple chat app
65 | - [Browser Pub/Sub](https://github.com/libp2p/js-libp2p-example-browser-pubsub) - Using Pub/Sub between browsers
66 |
67 | There is also [universal connectivity](https://github.com/libp2p/universal-connectivity/tree/main) demo that shows of how many different libp2p implementations can be connected together.
68 |
69 | ## Contribute
70 |
71 | See [CONTRIBUTING.md](https://github.com/libp2p/js-libp2p-examples/blob/main/CONTRIBUTING.md).
72 |
73 | ## License
74 |
75 | Licensed under either of
76 |
77 | - Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-examples/blob/main/LICENSE-APACHE) / )
78 | - MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-examples/blob/main/LICENSE-MIT) / )
79 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-auto-tls/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-auto-tls/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-auto-tls/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-auto-tls/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-auto-tls/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-auto-tls/auto-confirm.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: ["off"] */
2 |
3 | /* eslint-env mocha */
4 |
5 | import { noise } from '@chainsafe/libp2p-noise'
6 | import { yamux } from '@chainsafe/libp2p-yamux'
7 | import { autoTLS } from '@ipshipyard/libp2p-auto-tls'
8 | import { loadOrCreateSelfKey } from '@libp2p/config'
9 | import { identify, identifyPush } from '@libp2p/identify'
10 | import { keychain } from '@libp2p/keychain'
11 | import { uPnPNAT } from '@libp2p/upnp-nat'
12 | import { webSockets } from '@libp2p/websockets'
13 | import { WebSocketsSecure } from '@multiformats/multiaddr-matcher'
14 | import { LevelDatastore } from 'datastore-level'
15 | import { createLibp2p } from 'libp2p'
16 |
17 | const datastore = new LevelDatastore('./db')
18 | await datastore.open()
19 |
20 | const privateKey = await loadOrCreateSelfKey(datastore)
21 |
22 | const libp2p = await createLibp2p({
23 | privateKey,
24 | datastore,
25 | addresses: {
26 | listen: [
27 | '/ip4/0.0.0.0/tcp/0/ws',
28 | '/ip6/::/tcp/0/ws'
29 | ]
30 | },
31 | transports: [
32 | webSockets()
33 | ],
34 | connectionEncrypters: [
35 | noise()
36 | ],
37 | streamMuxers: [
38 | yamux()
39 | ],
40 | services: {
41 | // needed to run KAD-DHT and to be contacted by libp2p.direct
42 | identify: identify(),
43 | identifyPush: identifyPush(),
44 |
45 | // used to securely store the certificate for use after a restart
46 | keychain: keychain(),
47 |
48 | // requests a certificate and makes it available to libp2p, trusts that
49 | // `libp2p.direct` will answer DNS requests successfully
50 | autoTLS: autoTLS({
51 | autoConfirmAddress: true
52 | }),
53 |
54 | // opens ports on your router to allow libp2p.direct to dial us back - N.b
55 | // uPNP must be enabled for this to work. Trusts that network traffic will
56 | // reach us after this is done.
57 | uPnPNAT: uPnPNAT({
58 | autoConfirmAddress: true
59 | })
60 | }
61 | })
62 |
63 | libp2p.addEventListener('certificate:provision', () => {
64 | console.info('A TLS certificate was provisioned')
65 |
66 | const interval = setInterval(() => {
67 | const mas = libp2p
68 | .getMultiaddrs()
69 | .filter(ma => WebSocketsSecure.exactMatch(ma) && ma.toString().includes('/sni/'))
70 | .map(ma => ma.toString())
71 |
72 | if (mas.length > 0) {
73 | console.info('addresses:')
74 | console.info(mas.join('\n'))
75 | clearInterval(interval)
76 | }
77 | }, 1_000)
78 | })
79 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-auto-tls/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-auto-tls",
3 | "version": "0.0.0",
4 | "description": "How to get a TLS certificate automatically",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-examples/tree/master/examples/js-libp2p-example-pnet#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "scripts": {
15 | "test": "echo 'Cannot test in CI'"
16 | },
17 | "type": "module",
18 | "dependencies": {
19 | "@chainsafe/libp2p-noise": "^16.0.0",
20 | "@chainsafe/libp2p-yamux": "^7.0.0",
21 | "@ipshipyard/libp2p-auto-tls": "^1.0.0",
22 | "@libp2p/autonat": "^2.0.13",
23 | "@libp2p/bootstrap": "^11.0.14",
24 | "@libp2p/config": "^1.0.0",
25 | "@libp2p/identify": "^3.0.13",
26 | "@libp2p/kad-dht": "^15.0.0",
27 | "@libp2p/keychain": "^5.0.11",
28 | "@libp2p/ping": "^2.0.27",
29 | "@libp2p/upnp-nat": "^3.0.1",
30 | "@libp2p/websockets": "^9.1.0",
31 | "@multiformats/multiaddr-matcher": "^1.6.0",
32 | "datastore-level": "^11.0.1",
33 | "libp2p": "^2.0.0"
34 | },
35 | "private": true
36 | }
37 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-auto-tls/trust-free.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: ["off"] */
2 |
3 | /* eslint-env mocha */
4 |
5 | import { noise } from '@chainsafe/libp2p-noise'
6 | import { yamux } from '@chainsafe/libp2p-yamux'
7 | import { autoTLS } from '@ipshipyard/libp2p-auto-tls'
8 | import { autoNAT } from '@libp2p/autonat'
9 | import { bootstrap } from '@libp2p/bootstrap'
10 | import { loadOrCreateSelfKey } from '@libp2p/config'
11 | import { identify, identifyPush } from '@libp2p/identify'
12 | import { kadDHT, removePrivateAddressesMapper } from '@libp2p/kad-dht'
13 | import { keychain } from '@libp2p/keychain'
14 | import { ping } from '@libp2p/ping'
15 | import { tcp } from '@libp2p/tcp'
16 | import { uPnPNAT } from '@libp2p/upnp-nat'
17 | import { webSockets } from '@libp2p/websockets'
18 | import { WebSocketsSecure } from '@multiformats/multiaddr-matcher'
19 | import { LevelDatastore } from 'datastore-level'
20 | import { createLibp2p } from 'libp2p'
21 |
22 | const datastore = new LevelDatastore('./db')
23 | await datastore.open()
24 |
25 | const privateKey = await loadOrCreateSelfKey(datastore)
26 |
27 | const libp2p = await createLibp2p({
28 | privateKey,
29 | datastore,
30 | addresses: {
31 | listen: [
32 | '/ip4/0.0.0.0/tcp/0/ws',
33 | '/ip6/::/tcp/0/ws'
34 | ]
35 | },
36 | transports: [
37 | webSockets(),
38 | tcp()
39 | ],
40 | connectionEncrypters: [
41 | noise()
42 | ],
43 | streamMuxers: [
44 | yamux()
45 | ],
46 | services: {
47 | // needed to run KAD-DHT and to be contacted by libp2p.direct
48 | identify: identify(),
49 | identifyPush: identifyPush(),
50 | ping: ping(),
51 |
52 | // used to securely store the certificate for use after a restart
53 | keychain: keychain(),
54 |
55 | // requests a certificate and makes it available to libp2p
56 | autoTLS: autoTLS(),
57 |
58 | // opens ports on your router to allow libp2p.direct to dial us back - N.b
59 | // uPNP must be enabled for this to work
60 | uPnPNAT: uPnPNAT(),
61 |
62 | // verifies that our reported public addresses are dialable
63 | autoNAT: autoNAT(),
64 |
65 | // used to find peers to run AutoNAT
66 | aminoDHT: kadDHT({
67 | protocol: '/ipfs/kad/1.0.0',
68 | peerInfoMapper: removePrivateAddressesMapper
69 | }),
70 |
71 | // these peers help us fill our DHT routing table
72 | bootstrap: bootstrap({
73 | list: [
74 | '/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
75 | '/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
76 | '/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt',
77 | '/dnsaddr/va1.bootstrap.libp2p.io/p2p/12D3KooWKnDdG3iXw9eTFijk3EWSunZcFi54Zka4wmtqtt6rPxc8',
78 | '/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ'
79 | ]
80 | })
81 | }
82 | })
83 |
84 | libp2p.addEventListener('certificate:provision', () => {
85 | console.info('A TLS certificate was provisioned')
86 |
87 | const interval = setInterval(() => {
88 | const mas = libp2p
89 | .getMultiaddrs()
90 | .filter(ma => WebSocketsSecure.exactMatch(ma) && ma.toString().includes('/sni/'))
91 | .map(ma => ma.toString())
92 |
93 | if (mas.length > 0) {
94 | console.info('addresses:')
95 | console.info(mas.join('\n'))
96 | clearInterval(interval)
97 | }
98 | }, 1_000)
99 | })
100 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/README.md:
--------------------------------------------------------------------------------
1 | # @libp2p/example-browser-pubsub
2 |
3 | [](http://libp2p.io/)
4 | [](https://discuss.libp2p.io)
5 | [](https://codecov.io/gh/libp2p/js-libp2p-examples)
6 | [](https://github.com/libp2p/js-libp2p-examples/actions/workflows/ci.yml?query=branch%3Amain)
7 |
8 | > User libp2p pubsub in browsers
9 |
10 | This example leverages the [vite bundler](https://vitejs.dev/) to compile and serve the libp2p code in the browser. You can use other bundlers such as Webpack, but we will not be covering them here.
11 |
12 | ## Table of contents
13 |
14 | - [Setup](#setup)
15 | - [Running](#running)
16 | - [Why do I need a Relay Server?](#why-do-i-need-a-relay-server)
17 | - [Start the Relay Server](#start-the-relay-server)
18 | - [Running the Example](#running-the-example)
19 | - [Need help?](#need-help)
20 | - [License](#license)
21 | - [Contribution](#contribution)
22 |
23 | ## Setup
24 |
25 | 1. Install example dependencies
26 | ```console
27 | $ npm install
28 | ```
29 | 2. Open 2 terminal windows in the `./src` directory.
30 |
31 | ## Running
32 |
33 | This example has three components. Two browser windows which will send pubsub messages and a relay server that they will use to establish the initial connection.
34 |
35 | ### Why do I need a Relay Server?
36 |
37 | The only transport available to browser nodes that lets them be dialed by remote peers is the [WebRTC](https://www.npmjs.com/package/@libp2p/webrtc) transport.
38 |
39 | This transport requires an initial [handshake](https://en.wikipedia.org/wiki/Session_Description_Protocol) to be done out-of-band, during which the two peers exchange their capabilities, addresses and open ports.
40 |
41 | We use a [Circuit Relay](https://docs.libp2p.io/concepts/nat/circuit-relay/) server to establish an initial communication channel between the two browsers for this process, after which they will have negotiated a peer-to-peer connection and the relay will no longer be used.
42 |
43 | ```mermaid
44 | sequenceDiagram
45 | Browser A->>Relay: Create reservation
46 | activate Relay
47 | Browser B->>Relay: Dial Browser A
48 | Relay->>Browser A: Relayed dial from Browser B
49 | Browser B->>Relay: WebRTC handshake request
50 | Relay->>Browser A: Relayed WebRTC handshake request
51 | Browser A->>Relay: WebRTC handshake response
52 | Relay->>Browser B: Relayed WebRTC handshake response
53 | deactivate Relay
54 | Browser B->>Browser A: WebRTC connection
55 | ```
56 |
57 | ### Start the Relay Server
58 |
59 | For browsers to communicate, we first need to run the libp2p relay server:
60 |
61 | ```console
62 | $ npm run relay
63 | ```
64 |
65 | Copy one of the multiaddresses in the output.
66 |
67 | ### Running the Example
68 |
69 | Start the Vite server:
70 |
71 | ```console
72 | $ npm start
73 | ```
74 |
75 | A browser window will automatically open. Let's call this `Browser A`.
76 |
77 | 1. Paste the copied multiaddress from the relay server, paste it into the `Dial MultiAddr` input and click the `Connect` button
78 | 2. `Browser A` is now connected to the relay server
79 | 3. Copy the multiaddress located after the `Listening on` message
80 |
81 | Now open a second browser with the url `http://localhost:5173/`. Let's call this `Browser B`.
82 |
83 | 1. Using the copied multiaddress from `Listening on` section in `Browser A`, paste it into the `Remote MultiAddress` input and click the `Connect` button
84 | 2. `Browser B` is now connected to `Browser A`
85 |
86 | You can now shut down the relay server if you wish.
87 |
88 | 1. In both `Browser A` and `Browser B`, enter the same topic name in the "Subscribe to topic" input and click the "Subscribe" button
89 | 2. In either browser, enter a message in the `Send Message to Topic` field and click "Send"
90 |
91 | You should see the message appear in the output section towards the bottom of the other browser window.
92 |
93 | ## Need help?
94 |
95 | - Read the [js-libp2p documentation](https://github.com/libp2p/js-libp2p/tree/main/doc)
96 | - Check out the [js-libp2p API docs](https://libp2p.github.io/js-libp2p/)
97 | - Check out the [general libp2p documentation](https://docs.libp2p.io) for tips, how-tos and more
98 | - Read the [libp2p specs](https://github.com/libp2p/specs)
99 | - Ask a question on the [js-libp2p discussion board](https://github.com/libp2p/js-libp2p/discussions)
100 |
101 | ## License
102 |
103 | Licensed under either of
104 |
105 | - Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / )
106 | - MIT ([LICENSE-MIT](LICENSE-MIT) / )
107 |
108 | ## Contribution
109 |
110 | Unless you explicitly state otherwise, any contribution intentionally submitted
111 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
112 | dual licensed as above, without any additional terms or conditions.
113 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | js-libp2p browser pubsub
7 |
24 |
25 |
26 | libp2p Browser PubSub example
27 | This example demonstrates the pubsub API running in a browser
28 |
29 | Start a relay using the command line: $ node ./relay.js
30 | Relay listening on multiaddr(s): [
31 | '${multiaddr}'
32 | ]
33 |
34 | Copy the relay's multiaddr and use the "Dial Multaddr" section to dial the relay
35 | Wait for a WebRTC address to appear in the "Listening Addresses" area
36 | Open the same page in another browser window
37 | Use the "Dial Multiaddr" section in the second window to dial the WebRTC address from the first
38 | Subscribe both windows to the same topic using the "PubSub" section
39 | Send messages between the windows using the "PubSub" section
40 |
41 |
42 |
43 |
Node
44 |
Dial MultiAddr
45 |
46 |
Connect
47 |
48 |
PeerId
49 |
50 |
51 |
Listening Addresses
52 |
55 |
56 |
Connected Peers
57 |
60 |
61 |
62 |
63 |
PubSub
64 |
Subscribe to topic
65 |
66 |
Subscribe
67 |
68 |
Topic Peers
69 |
72 |
73 |
Send Message to Topic
74 |
75 |
Send
76 |
77 |
78 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-browser-pubsub",
3 | "version": "1.0.0",
4 | "description": "How to use libp2p pubsub in browsers",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-example-browser-pubsub#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "start": "vite",
17 | "build": "vite build",
18 | "relay": "node relay.js",
19 | "test:firefox": "npm run build && playwright test --browser=firefox test",
20 | "test:chrome": "npm run build && playwright test test",
21 | "test": "npm run build && test-browser-example test"
22 | },
23 | "dependencies": {
24 | "@chainsafe/libp2p-gossipsub": "^14.0.0",
25 | "@chainsafe/libp2p-noise": "^16.0.0",
26 | "@chainsafe/libp2p-yamux": "^7.0.0",
27 | "@libp2p/circuit-relay-v2": "^3.0.0",
28 | "@libp2p/dcutr": "^2.0.0",
29 | "@libp2p/identify": "^3.0.0",
30 | "@libp2p/webrtc": "^5.0.0",
31 | "@libp2p/websockets": "^9.0.0",
32 | "@multiformats/multiaddr": "^12.3.1",
33 | "libp2p": "^2.0.0",
34 | "vite": "^6.0.3"
35 | },
36 | "devDependencies": {
37 | "test-ipfs-example": "^1.0.0"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/relay.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { circuitRelayServer } from '@libp2p/circuit-relay-v2'
6 | import { identify } from '@libp2p/identify'
7 | import { webSockets } from '@libp2p/websockets'
8 | import * as filters from '@libp2p/websockets/filters'
9 | import { createLibp2p } from 'libp2p'
10 |
11 | const server = await createLibp2p({
12 | addresses: {
13 | listen: ['/ip4/127.0.0.1/tcp/0/ws']
14 | },
15 | transports: [
16 | webSockets({
17 | filter: filters.all
18 | })
19 | ],
20 | connectionEncrypters: [noise()],
21 | streamMuxers: [yamux()],
22 | services: {
23 | identify: identify(),
24 | relay: circuitRelayServer({
25 | reservations: {
26 | maxReservations: Infinity
27 | }
28 | })
29 | }
30 | })
31 |
32 | console.log('Relay listening on multiaddr(s): ', server.getMultiaddrs().map((ma) => ma.toString()))
33 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/test/index.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import { noise } from '@chainsafe/libp2p-noise'
3 | import { yamux } from '@chainsafe/libp2p-yamux'
4 | import { circuitRelayServer } from '@libp2p/circuit-relay-v2'
5 | import { identify } from '@libp2p/identify'
6 | import { webSockets } from '@libp2p/websockets'
7 | import * as filters from '@libp2p/websockets/filters'
8 | import { createLibp2p } from 'libp2p'
9 | import { setup, expect } from 'test-ipfs-example/browser'
10 |
11 | // Setup
12 | const test = setup()
13 |
14 | // DOM
15 | const connectBtn = '#dial-multiaddr-button'
16 | const connectAddr = '#dial-multiaddr-input'
17 | const sendMessageInput = '#send-topic-message-input'
18 | const sendMessageBtn = '#send-topic-message-button'
19 | const output = '#output'
20 | const listeningAddresses = '#listening-addresses'
21 | const subscribeInput = '#subscribe-topic-input'
22 | const subscribeBtn = '#subscribe-topic-button'
23 | const topicPeers = '#topic-peers'
24 | const peerId = '#peer-id'
25 |
26 | let url
27 |
28 | // we spawn a js libp2p relay
29 | async function spawnRelay () {
30 | const relayNode = await createLibp2p({
31 | addresses: {
32 | listen: ['/ip4/127.0.0.1/tcp/0/ws']
33 | },
34 | transports: [
35 | webSockets({
36 | filter: filters.all
37 | })
38 | ],
39 | connectionEncrypters: [noise()],
40 | streamMuxers: [yamux()],
41 | services: {
42 | identify: identify(),
43 | relay: circuitRelayServer()
44 | }
45 | })
46 |
47 | const relayNodeAddr = relayNode.getMultiaddrs()[0].toString()
48 |
49 | return { relayNode, relayNodeAddr }
50 | }
51 |
52 | test.describe('pubsub browser example:', () => {
53 | let relayNode
54 | let relayNodeAddr
55 |
56 | // eslint-disable-next-line no-empty-pattern
57 | test.beforeAll(async ({ servers }, testInfo) => {
58 | testInfo.setTimeout(5 * 60_000)
59 | const r = await spawnRelay()
60 | relayNode = r.relayNode
61 | relayNodeAddr = r.relayNodeAddr
62 | url = servers[0].url
63 | }, {})
64 |
65 | test.afterAll(() => {
66 | relayNode.stop()
67 | })
68 |
69 | test.beforeEach(async ({ page }) => {
70 | await page.goto(url)
71 | })
72 |
73 | test('should connect via a relay node', async ({ page: pageA, context }) => {
74 | // load second page
75 | const pageB = await context.newPage()
76 | await pageB.goto(url)
77 |
78 | // load page peer ids
79 | const pageAPeerId = await pageA.textContent(peerId)
80 | const pageBPeerId = await pageB.textContent(peerId)
81 |
82 | // connect the first page to the relay
83 | const webRTCAddressA = await dialRelay(pageA, relayNodeAddr)
84 |
85 | // dial first page from second page over relay
86 | await dialPeerOverRelay(pageB, webRTCAddressA)
87 |
88 | // stop the relay
89 | await relayNode.stop()
90 |
91 | const topicName = `topic-${Date.now()}`
92 |
93 | // subscribe to pubsub topic
94 | await subscribeToTopic(pageA, topicName)
95 | await subscribeToTopic(pageB, topicName)
96 |
97 | // wait for peers to appear in topic peers
98 | await waitForTopicPeers(pageA, pageBPeerId)
99 | await waitForTopicPeers(pageB, pageAPeerId)
100 |
101 | // send a message from one to the other
102 | await sendMessage(pageA, 'hello A', pageB)
103 | })
104 | })
105 |
106 | async function subscribeToTopic (page, topic) {
107 | // subscribe to the topic
108 | await page.fill(subscribeInput, topic)
109 | await page.click(subscribeBtn)
110 |
111 | // check the message was echoed back
112 | const outputLocator = page.locator(output)
113 | await expect(outputLocator).toContainText(`Subscribing to '${topic}'`)
114 | }
115 |
116 | async function waitForTopicPeers (page, otherPeer) {
117 | const outputLocator = page.locator(topicPeers)
118 | await expect(outputLocator).toContainText(otherPeer)
119 | }
120 |
121 | async function sendMessage (pageA, message, pageB) {
122 | // subscribe to the topic
123 | await pageA.fill(sendMessageInput, message)
124 | await pageA.click(sendMessageBtn)
125 |
126 | // check the message was received
127 | const outputLocator = pageB.locator(output)
128 | await expect(outputLocator).toContainText(message)
129 | }
130 |
131 | async function dialRelay (page, address) {
132 | // add the relay multiaddr to the input field and submit
133 | await page.fill(connectAddr, address)
134 | await page.click(connectBtn)
135 |
136 | const outputLocator = page.locator(output)
137 | await expect(outputLocator).toContainText(`Dialing '${address}'`)
138 | await expect(outputLocator).toContainText(`Connected to '${address}'`)
139 |
140 | const multiaddrsLocator = page.locator(listeningAddresses)
141 | await expect(multiaddrsLocator).toHaveText(/webrtc/)
142 |
143 | const multiaddrs = await page.textContent(listeningAddresses)
144 | const addr = multiaddrs.split(address).filter(str => str.includes('webrtc')).pop()
145 |
146 | return address + addr
147 | }
148 |
149 | async function dialPeerOverRelay (page, address) {
150 | // add the go libp2p multiaddr to the input field and submit
151 | await page.fill(connectAddr, address)
152 | await page.click(connectBtn)
153 |
154 | const outputLocator = page.locator(output)
155 | await expect(outputLocator).toContainText(`Dialing '${address}'`)
156 | await expect(outputLocator).toContainText(`Connected to '${address}'`)
157 | }
158 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-browser-pubsub/vite.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | build: {
3 | target: 'es2022'
4 | },
5 | optimizeDeps: {
6 | esbuildOptions: { target: 'es2022', supported: { bigint: true } }
7 | },
8 | server: {
9 | open: true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/README.md:
--------------------------------------------------------------------------------
1 | # @libp2p/example-chat
2 |
3 | [](http://libp2p.io/)
4 | [](https://discuss.libp2p.io)
5 | [](https://codecov.io/gh/libp2p/js-libp2p-examples)
6 | [](https://github.com/libp2p/js-libp2p-examples/actions/workflows/ci.yml?query=branch%3Amain)
7 |
8 | > An example chat app using libp2p
9 |
10 | ## Table of contents
11 |
12 | - [Setup](#setup)
13 | - [Running](#running)
14 | - [Need help?](#need-help)
15 | - [License](#license)
16 | - [Contribution](#contribution)
17 |
18 | ## Setup
19 |
20 | 1. Install example dependencies
21 | ```console
22 | $ npm install
23 | ```
24 | 2. Open 2 terminal windows in the `./src` directory.
25 |
26 | ## Running
27 |
28 | 1. Run the listener in window 1, `node listener.js`
29 | 2. Run the dialer in window 2, `node dialer.js`
30 | 3. Wait until the two peers discover each other
31 | 4. Type a message in either window and hit *enter*
32 | 5. Tell yourself secrets to your hearts content!
33 |
34 | ## Need help?
35 |
36 | - Read the [js-libp2p documentation](https://github.com/libp2p/js-libp2p/tree/main/doc)
37 | - Check out the [js-libp2p API docs](https://libp2p.github.io/js-libp2p/)
38 | - Check out the [general libp2p documentation](https://docs.libp2p.io) for tips, how-tos and more
39 | - Read the [libp2p specs](https://github.com/libp2p/specs)
40 | - Ask a question on the [js-libp2p discussion board](https://github.com/libp2p/js-libp2p/discussions)
41 |
42 | ## License
43 |
44 | Licensed under either of
45 |
46 | - Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / )
47 | - MIT ([LICENSE-MIT](LICENSE-MIT) / )
48 |
49 | ## Contribution
50 |
51 | Unless you explicitly state otherwise, any contribution intentionally submitted
52 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
53 | dual licensed as above, without any additional terms or conditions.
54 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-chat",
3 | "version": "0.0.0",
4 | "description": "An example chat app using libp2p",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-example-chat#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "test": "test-node-example test/*"
17 | },
18 | "dependencies": {
19 | "@chainsafe/libp2p-noise": "^16.0.0",
20 | "@chainsafe/libp2p-yamux": "^7.0.0",
21 | "@libp2p/mdns": "^11.0.1",
22 | "@libp2p/tcp": "^10.0.0",
23 | "@libp2p/websockets": "^9.0.0",
24 | "@multiformats/multiaddr": "^12.3.1",
25 | "@nodeutils/defaults-deep": "^1.1.0",
26 | "it-length-prefixed": "^10.0.1",
27 | "it-map": "^3.0.3",
28 | "it-pipe": "^3.0.1",
29 | "libp2p": "^2.0.0",
30 | "p-defer": "^4.0.0",
31 | "uint8arrays": "^5.1.0"
32 | },
33 | "devDependencies": {
34 | "test-ipfs-example": "^1.1.0"
35 | },
36 | "private": true
37 | }
38 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/src/dialer.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { createLibp2p } from './libp2p.js'
4 | import { stdinToStream, streamToConsole } from './stream.js'
5 |
6 | async function run () {
7 | // Create a new libp2p node on localhost with a randomly chosen port
8 | const dialer = await createLibp2p({
9 | addresses: {
10 | listen: ['/ip4/0.0.0.0/tcp/0']
11 | }
12 | })
13 |
14 | // Output this node's address
15 | console.log('Dialer ready, listening on:')
16 | dialer.getMultiaddrs().forEach((ma) => {
17 | console.log(ma.toString())
18 | })
19 |
20 | dialer.addEventListener('peer:discovery', (evt) => {
21 | console.info('peer:discovery', evt.detail)
22 |
23 | // Dial to the remote peer (the "listener")
24 | dialer.dialProtocol(evt.detail.multiaddrs, '/chat/1.0.0')
25 | .then(stream => {
26 | console.log('Dialer dialed to listener on protocol: /chat/1.0.0')
27 | console.log('Type a message and see what happens')
28 |
29 | // Send stdin to the stream
30 | stdinToStream(stream)
31 | // Read the stream and output to console
32 | streamToConsole(stream)
33 | })
34 | })
35 | }
36 |
37 | run()
38 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/src/libp2p.js:
--------------------------------------------------------------------------------
1 | import { noise } from '@chainsafe/libp2p-noise'
2 | import { yamux } from '@chainsafe/libp2p-yamux'
3 | import { mdns } from '@libp2p/mdns'
4 | import { tcp } from '@libp2p/tcp'
5 | import { webSockets } from '@libp2p/websockets'
6 | import defaultsDeep from '@nodeutils/defaults-deep'
7 | import { createLibp2p as create } from 'libp2p'
8 |
9 | export async function createLibp2p (_options) {
10 | const defaults = {
11 | transports: [
12 | tcp(),
13 | webSockets()
14 | ],
15 | streamMuxers: [
16 | yamux()
17 | ],
18 | connectionEncrypters: [
19 | noise()
20 | ],
21 | peerDiscovery: [
22 | mdns()
23 | ]
24 | }
25 |
26 | return create(defaultsDeep(_options, defaults))
27 | }
28 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/src/listener.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { createLibp2p } from './libp2p.js'
4 | import { stdinToStream, streamToConsole } from './stream.js'
5 |
6 | async function run () {
7 | // Create a new libp2p node with the given multi-address
8 | const listener = await createLibp2p({
9 | addresses: {
10 | listen: ['/ip4/0.0.0.0/tcp/10333']
11 | }
12 | })
13 |
14 | // Log a message when a remote peer connects to us
15 | listener.addEventListener('peer:connect', (evt) => {
16 | const remotePeer = evt.detail
17 | console.log('connected to: ', remotePeer.toString())
18 | })
19 |
20 | // Handle messages for the protocol
21 | await listener.handle('/chat/1.0.0', async ({ stream }) => {
22 | // Send stdin to the stream
23 | stdinToStream(stream)
24 | // Read the stream and output to console
25 | streamToConsole(stream)
26 | })
27 |
28 | // Output listen addresses to the console
29 | console.log('Listener ready, listening on:')
30 | listener.getMultiaddrs().forEach((ma) => {
31 | console.log(ma.toString())
32 | })
33 | }
34 |
35 | run()
36 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/src/stream.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import * as lp from 'it-length-prefixed'
4 | import map from 'it-map'
5 | import { pipe } from 'it-pipe'
6 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
7 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
8 |
9 | export function stdinToStream (stream) {
10 | // Read utf-8 from stdin
11 | process.stdin.setEncoding('utf8')
12 | pipe(
13 | // Read from stdin (the source)
14 | process.stdin,
15 | // Turn strings into buffers
16 | (source) => map(source, (string) => uint8ArrayFromString(string)),
17 | // Encode with length prefix (so receiving side knows how much data is coming)
18 | (source) => lp.encode(source),
19 | // Write to the stream (the sink)
20 | stream.sink
21 | )
22 | }
23 |
24 | export function streamToConsole (stream) {
25 | pipe(
26 | // Read from the stream (the source)
27 | stream.source,
28 | // Decode length-prefixed data
29 | (source) => lp.decode(source),
30 | // Turn buffers into strings
31 | (source) => map(source, (buf) => uint8ArrayToString(buf.subarray())),
32 | // Sink function
33 | async function (source) {
34 | // For each chunk of data
35 | for await (const msg of source) {
36 | // Output the data as a utf8 string
37 | console.log('> ' + msg.toString().replace('\n', ''))
38 | }
39 | }
40 | )
41 | }
42 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-chat/test/index.spec.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import pDefer from 'p-defer'
4 | import { matchOutput } from 'test-ipfs-example/node'
5 |
6 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
7 |
8 | const messageReceived = pDefer()
9 | const message = 'test message'
10 |
11 | // Step 1 process
12 | process.stdout.write('node listener.js\n')
13 |
14 | const {
15 | process: listener
16 | } = await matchOutput(/Listener ready, listening on/g, 'node', [path.resolve(__dirname, '../src/listener.js')])
17 |
18 | // receive message
19 | listener.stdout.addListener('data', (buf) => {
20 | if (buf.toString().includes(message)) {
21 | messageReceived.resolve()
22 | }
23 | })
24 |
25 | process.stdout.write('==================================================================\n')
26 |
27 | // Step 2 process
28 | process.stdout.write('node dialer.js\n')
29 |
30 | const {
31 | process: dialer
32 | } = await matchOutput(/Type a message and see what happens/g, 'node', [path.resolve(__dirname, '../src/dialer.js')])
33 |
34 | // send message
35 | dialer.stdin.write(message)
36 | dialer.stdin.write('\n')
37 |
38 | process.stdout.write('==================================================================\n')
39 |
40 | await messageReceived.promise
41 |
42 | process.stdout.write('chat message received\n')
43 |
44 | dialer.kill()
45 | listener.kill()
46 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-circuit-relay/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-circuit-relay/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-circuit-relay/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-circuit-relay/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-circuit-relay/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-circuit-relay/dialer.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { circuitRelayTransport } from '@libp2p/circuit-relay-v2'
6 | import { identify } from '@libp2p/identify'
7 | import { webSockets } from '@libp2p/websockets'
8 | import { multiaddr } from '@multiformats/multiaddr'
9 | import { createLibp2p } from 'libp2p'
10 |
11 | async function main () {
12 | const listenNodeAddr = process.argv[2]
13 | if (!listenNodeAddr) {
14 | throw new Error('The listening node address needs to be specified')
15 | }
16 |
17 | const node = await createLibp2p({
18 | transports: [
19 | webSockets(),
20 | circuitRelayTransport()
21 | ],
22 | connectionEncrypters: [
23 | noise()
24 | ],
25 | streamMuxers: [
26 | yamux()
27 | ],
28 | services: {
29 | identify: identify()
30 | }
31 | })
32 |
33 | console.log(`Node started with id ${node.peerId.toString()}`)
34 |
35 | const ma = multiaddr(listenNodeAddr)
36 | const conn = await node.dial(ma, {
37 | signal: AbortSignal.timeout(10_000)
38 | })
39 | console.log(`Connected to the listening node via ${conn.remoteAddr.toString()}`)
40 | }
41 |
42 | main()
43 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-circuit-relay/listener.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { circuitRelayTransport } from '@libp2p/circuit-relay-v2'
6 | import { identify } from '@libp2p/identify'
7 | import { webSockets } from '@libp2p/websockets'
8 | import { multiaddr } from '@multiformats/multiaddr'
9 | import { createLibp2p } from 'libp2p'
10 |
11 | async function main () {
12 | const relayAddr = process.argv[2]
13 | if (!relayAddr) {
14 | throw new Error('the relay address needs to be specified as a parameter')
15 | }
16 |
17 | const node = await createLibp2p({
18 | addresses: {
19 | listen: [
20 | '/p2p-circuit'
21 | ]
22 | },
23 | transports: [
24 | webSockets(),
25 | circuitRelayTransport()
26 | ],
27 | connectionEncrypters: [
28 | noise()
29 | ],
30 | streamMuxers: [
31 | yamux()
32 | ],
33 | services: {
34 | identify: identify()
35 | }
36 | })
37 |
38 | console.log(`Node started with id ${node.peerId.toString()}`)
39 |
40 | const conn = await node.dial(multiaddr(relayAddr))
41 |
42 | console.log(`Connected to the relay ${conn.remotePeer.toString()}`)
43 |
44 | // Wait for connection and relay to be bind for the example purpose
45 | node.addEventListener('self:peer:update', (evt) => {
46 | // Updated self multiaddrs?
47 | console.log(`Listening on a relay address of ${node.getMultiaddrs()[0].toString()}`)
48 | })
49 | }
50 |
51 | main()
52 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-circuit-relay/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-circuit-relay",
3 | "version": "0.0.0",
4 | "description": "How to use Circuit Relay to connect two nodes",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-example-circuit-relay#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "test": "test-node-example test/*"
17 | },
18 | "dependencies": {
19 | "@chainsafe/libp2p-noise": "^16.0.0",
20 | "@chainsafe/libp2p-yamux": "^7.0.0",
21 | "@libp2p/circuit-relay-v2": "^3.0.0",
22 | "@libp2p/identify": "^3.0.0",
23 | "@libp2p/websockets": "^9.0.0",
24 | "@multiformats/multiaddr": "^12.3.1",
25 | "libp2p": "^2.0.0"
26 | },
27 | "devDependencies": {
28 | "test-ipfs-example": "^1.1.0"
29 | },
30 | "private": true
31 | }
32 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-circuit-relay/relay.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { circuitRelayServer } from '@libp2p/circuit-relay-v2'
6 | import { identify } from '@libp2p/identify'
7 | import { webSockets } from '@libp2p/websockets'
8 | import { createLibp2p } from 'libp2p'
9 |
10 | async function main () {
11 | const node = await createLibp2p({
12 | addresses: {
13 | listen: ['/ip4/0.0.0.0/tcp/0/ws']
14 | // TODO check "What is next?" section
15 | },
16 | transports: [
17 | webSockets()
18 | ],
19 | connectionEncrypters: [
20 | noise()
21 | ],
22 | streamMuxers: [
23 | yamux()
24 | ],
25 | services: {
26 | identify: identify(),
27 | relay: circuitRelayServer()
28 | }
29 | })
30 |
31 | console.log(`Node started with id ${node.peerId.toString()}`)
32 | console.log('Listening on:')
33 | node.getMultiaddrs().forEach((ma) => console.log(ma.toString()))
34 | }
35 |
36 | main()
37 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-circuit-relay/test/index.spec.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { matchOutput, waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | // Step 1 process
8 | process.stdout.write('relay.js\n')
9 |
10 | const {
11 | process: relay,
12 | matches: [relayAddress]
13 | } = await matchOutput(/^(\/ip4\/.*)$/m, 'node', [path.resolve(__dirname, '../relay.js')])
14 |
15 | process.stdout.write('==================================================================\n')
16 |
17 | // Step 2 process
18 | process.stdout.write('listener.js\n')
19 |
20 | const {
21 | process: listener,
22 | matches: [, autoRelayAddr]
23 | } = await matchOutput(/^Listening on a relay address of (\/ip4\/.*)$/m, 'node', [path.resolve(__dirname, '../listener.js'), relayAddress])
24 |
25 | process.stdout.write('==================================================================\n')
26 |
27 | // Step 3 process
28 | process.stdout.write('dialer.js\n')
29 |
30 | await waitForOutput(`Connected to the listening node via ${autoRelayAddr}`, 'node', [path.resolve(__dirname, '../dialer.js'), autoRelayAddr])
31 |
32 | listener.kill()
33 | relay.kill()
34 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-connection-encryption/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-connection-encryption/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-connection-encryption/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-connection-encryption/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-connection-encryption/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-connection-encryption/README.md:
--------------------------------------------------------------------------------
1 | # @libp2p/example-connection-encryption
2 |
3 | [](http://libp2p.io/)
4 | [](https://discuss.libp2p.io)
5 | [](https://codecov.io/gh/libp2p/js-libp2p-examples)
6 | [](https://github.com/libp2p/js-libp2p-examples/actions/workflows/ci.yml?query=branch%3Amain)
7 |
8 | > An example of how to configure connection encrypters
9 |
10 | ## Table of contents
11 |
12 | - [Set up encrypted communications](#set-up-encrypted-communications)
13 | - [Need help?](#need-help)
14 | - [License](#license)
15 | - [Contribution](#contribution)
16 |
17 | All traffic sent over connections between two libp2p nodes is encrypted. This gives us peace of mind that the node we are talking to is the node we think we are talking to, and that no-one is able to eavesdrop or interfere with the data we are exchanging.
18 |
19 | You may have noticed that every time we dial the [multiaddr](https://multiformats.io/multiaddr) of a peer in libp2p space, we include the [PeerId](https://docs.libp2p.io/concepts/fundamentals/peers/#peer-id) at the end:
20 |
21 | ```
22 | /ip4/127.0.0.1/tcp/89765/p2p/12D3Foo
23 | ```
24 |
25 | For some types of `PeerID`, it is the public key of the remote node (Ed25519 and secp256k1) or, when the public key is too large to embed in a string, it can be the a hash of the public key (RSA).
26 |
27 | Including the `PeerID` in the multiaddr allows us to authenticate the remote peer by creating a crypto challenge that allows them to prove they hold the the private key that matches the public key we know.
28 |
29 | Once authenticated in this fashion we can proceed to encrypt/decrypt all traffic sent over the connection.
30 |
31 | There are several strategies for performing encryption, the most common uses the [Noise Protocol Framework](http://www.noiseprotocol.org/).
32 |
33 | js-libp2p also supports a plaintext "encryption" implementation that should not be used in production but is sometimes useful for testing.
34 |
35 | ## Set up encrypted communications
36 |
37 | To add them to your libp2p configuration, all you have to do is:
38 |
39 | ```JavaScript
40 | import { noise } from '@chainsafe/libp2p-noise'
41 | import { yamux } from '@chainsafe/libp2p-yamux'
42 | import { tcp } from '@libp2p/tcp'
43 | import { createLibp2p } from 'libp2p'
44 |
45 | const createNode = async () => {
46 | return await createLibp2p({
47 | transports: [ tcp() ],
48 | streamMuxers: [ yamux() ],
49 | // Attach noise as the crypto channel to use
50 | connectionEncrypters: [ noise() ]
51 | })
52 | }
53 | ```
54 |
55 | And that's it, from now on, all your libp2p communications are encrypted. Try running the example [noise.js](./noise.js) to see it working.
56 |
57 | To experiment with the plaintext implementation, run [plaintext.js](./plaintext.js).
58 |
59 | ## Need help?
60 |
61 | - Read the [js-libp2p documentation](https://github.com/libp2p/js-libp2p/tree/main/doc)
62 | - Check out the [js-libp2p API docs](https://libp2p.github.io/js-libp2p/)
63 | - Check out the [general libp2p documentation](https://docs.libp2p.io) for tips, how-tos and more
64 | - Read the [libp2p specs](https://github.com/libp2p/specs)
65 | - Ask a question on the [js-libp2p discussion board](https://github.com/libp2p/js-libp2p/discussions)
66 |
67 | ## License
68 |
69 | Licensed under either of
70 |
71 | - Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / )
72 | - MIT ([LICENSE-MIT](LICENSE-MIT) / )
73 |
74 | ## Contribution
75 |
76 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
77 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-connection-encryption/noise.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { tcp } from '@libp2p/tcp'
6 | import { pipe } from 'it-pipe'
7 | import { createLibp2p } from 'libp2p'
8 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
9 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
10 |
11 | const createNode = async () => {
12 | const node = await createLibp2p({
13 | addresses: {
14 | listen: ['/ip4/0.0.0.0/tcp/0']
15 | },
16 | transports: [tcp()],
17 | streamMuxers: [yamux()],
18 | connectionEncrypters: [noise()]
19 | })
20 |
21 | return node
22 | }
23 |
24 | const node1 = await createNode()
25 | const node2 = await createNode()
26 |
27 | node2.handle('/a-protocol', ({ stream }) => {
28 | pipe(
29 | stream,
30 | async function (source) {
31 | for await (const msg of source) {
32 | console.log(uint8ArrayToString(msg.subarray()))
33 | }
34 | }
35 | )
36 | })
37 |
38 | const stream = await node1.dialProtocol(node2.getMultiaddrs(), '/a-protocol')
39 |
40 | await pipe(
41 | [uint8ArrayFromString('This information is sent out encrypted to the other peer')],
42 | stream
43 | )
44 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-connection-encryption/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-connection-encryption",
3 | "version": "0.0.0",
4 | "description": "An example of how to configure connection encryption",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-example-connection-encryption#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "test": "test-node-example test/*"
17 | },
18 | "dependencies": {
19 | "@chainsafe/libp2p-noise": "^16.0.0",
20 | "@chainsafe/libp2p-yamux": "^7.0.0",
21 | "@libp2p/plaintext": "^2.0.0",
22 | "@libp2p/tcp": "^10.0.0",
23 | "it-pipe": "^3.0.1",
24 | "libp2p": "^2.0.0",
25 | "uint8arrays": "^5.1.0"
26 | },
27 | "devDependencies": {
28 | "test-ipfs-example": "^1.0.0"
29 | },
30 | "private": true
31 | }
32 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-connection-encryption/plaintext.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { yamux } from '@chainsafe/libp2p-yamux'
4 | import { plaintext } from '@libp2p/plaintext'
5 | import { tcp } from '@libp2p/tcp'
6 | import { pipe } from 'it-pipe'
7 | import { createLibp2p } from 'libp2p'
8 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
9 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
10 |
11 | const createNode = async () => {
12 | const node = await createLibp2p({
13 | addresses: {
14 | listen: ['/ip4/0.0.0.0/tcp/0']
15 | },
16 | transports: [tcp()],
17 | streamMuxers: [yamux()],
18 | connectionEncrypters: [plaintext()]
19 | })
20 |
21 | return node
22 | }
23 |
24 | const node1 = await createNode()
25 | const node2 = await createNode()
26 |
27 | node2.handle('/a-protocol', ({ stream }) => {
28 | pipe(
29 | stream,
30 | async function (source) {
31 | for await (const msg of source) {
32 | console.log(uint8ArrayToString(msg.subarray()))
33 | }
34 | }
35 | )
36 | })
37 |
38 | const stream = await node1.dialProtocol(node2.getMultiaddrs(), '/a-protocol')
39 |
40 | await pipe(
41 | [uint8ArrayFromString('This information is sent out encrypted to the other peer')],
42 | stream
43 | )
44 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-connection-encryption/test/index.spec.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | process.stdout.write('noise.js\n')
8 |
9 | await waitForOutput('This information is sent out encrypted to the other peer', 'node', [path.join(__dirname, '../noise.js')], {
10 | cwd: __dirname
11 | })
12 |
13 | process.stdout.write('plaintext.js\n')
14 |
15 | await waitForOutput('This information is sent out encrypted to the other peer', 'node', [path.join(__dirname, '../plaintext.js')], {
16 | cwd: __dirname
17 | })
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-custom-protocols/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-custom-protocols/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-custom-protocols/1-echo.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { tcp } from '@libp2p/tcp'
6 | import { pipe } from 'it-pipe'
7 | import { createLibp2p } from 'libp2p'
8 |
9 | async function createNode () {
10 | return await createLibp2p({
11 | addresses: {
12 | listen: [
13 | '/ip4/0.0.0.0/tcp/0'
14 | ]
15 | },
16 | connectionEncrypters: [
17 | noise()
18 | ],
19 | streamMuxers: [
20 | yamux()
21 | ],
22 | transports: [
23 | tcp()
24 | ]
25 | })
26 | }
27 |
28 | // create two nodes
29 | const remote = await createNode()
30 | const local = await createNode()
31 |
32 | // this is our protocol id
33 | const ECHO_PROTOCOL = '/echo/1.0.0'
34 |
35 | // the remote will handle incoming streams opened on the protocol
36 | await remote.handle(ECHO_PROTOCOL, ({ stream }) => {
37 | // pipe the stream output back to the stream input
38 | pipe(stream, stream)
39 | })
40 |
41 | // the local will dial the remote on the protocol stream
42 | const stream = await local.dialProtocol(remote.getMultiaddrs(), ECHO_PROTOCOL)
43 |
44 | // now it will write some data and read it back
45 | const output = await pipe(
46 | async function * () {
47 | // the stream input must be bytes
48 | yield new TextEncoder().encode('hello world')
49 | },
50 | stream,
51 | async (source) => {
52 | let string = ''
53 | const decoder = new TextDecoder()
54 |
55 | for await (const buf of source) {
56 | // buf is a `Uint8ArrayList` so we must turn it into a `Uint8Array`
57 | // before decoding it
58 | string += decoder.decode(buf.subarray())
59 | }
60 |
61 | return string
62 | }
63 | )
64 |
65 | console.info(`Echoed back to us: "${output}"`)
66 |
67 | await remote.stop()
68 | await local.stop()
69 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-custom-protocols/2-request-response.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { tcp } from '@libp2p/tcp'
6 | import { lpStream } from 'it-length-prefixed-stream'
7 | import { createLibp2p } from 'libp2p'
8 |
9 | async function createNode () {
10 | return await createLibp2p({
11 | addresses: {
12 | listen: [
13 | '/ip4/0.0.0.0/tcp/0'
14 | ]
15 | },
16 | connectionEncrypters: [
17 | noise()
18 | ],
19 | streamMuxers: [
20 | yamux()
21 | ],
22 | transports: [
23 | tcp()
24 | ]
25 | })
26 | }
27 |
28 | // create two nodes
29 | const remote = await createNode()
30 | const local = await createNode()
31 |
32 | // this is our protocol id
33 | const REQ_RESP_PROTOCOL = '/request-response/1.0.0'
34 |
35 | // the remote will handle incoming streams opened on the protocol
36 | await remote.handle(REQ_RESP_PROTOCOL, ({ stream }) => {
37 | Promise.resolve().then(async () => {
38 | // lpStream lets us read/write in a predetermined order
39 | const lp = lpStream(stream)
40 |
41 | // read the incoming request
42 | const req = await lp.read()
43 |
44 | // deserialize the query
45 | const query = JSON.parse(new TextDecoder().decode(req.subarray()))
46 |
47 | if (query.question === 'What is the air-speed velocity of an unladen swallow?') {
48 | // write the response
49 | await lp.write(new TextEncoder().encode(JSON.stringify({
50 | answer: 'Is that an African or a European swallow?'
51 | })))
52 | } else {
53 | // write the response
54 | await lp.write(new TextEncoder().encode(JSON.stringify({
55 | error: "What? I don't know?!"
56 | })))
57 | }
58 | })
59 | .catch(err => {
60 | stream.abort(err)
61 | })
62 | })
63 |
64 | // the local will dial the remote on the protocol stream
65 | const stream = await local.dialProtocol(remote.getMultiaddrs(), REQ_RESP_PROTOCOL)
66 |
67 | // lpStream lets us read/write in a predetermined order
68 | const lp = lpStream(stream)
69 |
70 | // send the query
71 | await lp.write(new TextEncoder().encode(JSON.stringify({
72 | question: 'What is the air-speed velocity of an unladen swallow?'
73 | })))
74 |
75 | // read the response
76 | const res = await lp.read()
77 | const output = JSON.parse(new TextDecoder().decode(res.subarray()))
78 |
79 | console.info(`The answer is: "${output.answer}"`)
80 |
81 | await remote.stop()
82 | await local.stop()
83 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-custom-protocols/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-custom-protocols/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-custom-protocols/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-custom-protocols/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-custom-protocols",
3 | "version": "0.0.0",
4 | "description": "How to create custom protocols for your app",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-example-custom-protocols#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "test": "test-node-example test/*"
17 | },
18 | "dependencies": {
19 | "@chainsafe/libp2p-noise": "^16.0.0",
20 | "@chainsafe/libp2p-yamux": "^7.0.0",
21 | "@libp2p/tcp": "^10.0.0",
22 | "@libp2p/websockets": "^9.0.0",
23 | "@multiformats/multiaddr": "^12.1.5",
24 | "@nodeutils/defaults-deep": "^1.1.0",
25 | "it-length-prefixed-stream": "^1.1.4",
26 | "it-pipe": "^3.0.1",
27 | "libp2p": "^2.0.0",
28 | "uint8arrays": "^5.1.0"
29 | },
30 | "devDependencies": {
31 | "test-ipfs-example": "^1.1.0"
32 | },
33 | "private": true
34 | }
35 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-custom-protocols/test/1-echo.spec.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | process.stdout.write('1-echo.js\n')
8 |
9 | await waitForOutput('Echoed back to us: "hello world"', 'node', [path.join(__dirname, '..', '1-echo.js')], {
10 | cwd: __dirname
11 | })
12 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-custom-protocols/test/2-request-response.spec.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | process.stdout.write('2-request-response.js\n')
8 |
9 | await waitForOutput('The answer is: "Is that an African or a European swallow?"', 'node', [path.join(__dirname, '..', '2-request-response.js')], {
10 | cwd: __dirname
11 | })
12 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/README.md:
--------------------------------------------------------------------------------
1 | # @libp2p/example-delegated-routing-example
2 |
3 | [](http://libp2p.io/)
4 | [](https://discuss.libp2p.io)
5 | [](https://codecov.io/gh/libp2p/js-libp2p-examples)
6 | [](https://github.com/libp2p/js-libp2p-examples/actions/workflows/ci.yml?query=branch%3Amain)
7 |
8 | > How to configure libp2p delegated routers
9 |
10 | ## Table of contents
11 |
12 | - [Running this example](#running-this-example)
13 | - [Finding Content Providers via the Delegate](#finding-content-providers-via-the-delegate)
14 | - [Finding Peers via the Delegate](#finding-peers-via-the-delegate)
15 | - [Need help?](#need-help)
16 | - [License](#license)
17 | - [Contribution](#contribution)
18 |
19 | Delegated routing allows a libp2p node running in a constrained environment (for example a browser) to offload network operations and queries to a more capable node running elsewhere.
20 |
21 | The [libp2p node](./src/libp2p.js) created by this app has no transports, connection encrypters or muxers - it uses only a [Delegated Routing V1 HTTP API client](https://specs.ipfs.tech/routing/http-routing-v1/) to look up CID providers and Peer Info from a more capable libp2p node running in a separate process.
22 |
23 | ## Running this example
24 |
25 | 1. Install the example dependencies
26 | ```console
27 | $ npm i
28 | ```
29 | 2. Start the Helia node in `./server.js` - this is the node we will delegate operations to
30 | ```console
31 | $ node ./server.js
32 | ```
33 | 3. Start the lightweight browser libp2p node
34 | ```console
35 | $ npm start
36 | ```
37 |
38 | This should open your browser to . If it does not, go ahead and do that now.
39 |
40 | ### Finding Content Providers via the Delegate
41 |
42 | 1. Enter the CID of the block you wish to find providers for, one is pre-filled for your convenience
43 | 2. Click "Find Providers"
44 | 3. If any exist, provders will start to appear in the box beneath the input fields
45 |
46 | ### Finding Peers via the Delegate
47 |
48 | 1. Enter the PeerId of the peer you wish to find, one is pre-filled for your convenience
49 | 2. Click "Find PeerInfo"
50 | 3. If found, multiaddrs for the peer will appear in the box beneath the input fields
51 |
52 | ## Need help?
53 |
54 | - Read the [js-libp2p documentation](https://github.com/libp2p/js-libp2p/tree/main/doc)
55 | - Check out the [js-libp2p API docs](https://libp2p.github.io/js-libp2p/)
56 | - Check out the [general libp2p documentation](https://docs.libp2p.io) for tips, how-tos and more
57 | - Read the [libp2p specs](https://github.com/libp2p/specs)
58 | - Ask a question on the [js-libp2p discussion board](https://github.com/libp2p/js-libp2p/discussions)
59 |
60 | ## License
61 |
62 | Licensed under either of
63 |
64 | - Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / )
65 | - MIT ([LICENSE-MIT](LICENSE-MIT) / )
66 |
67 | ## Contribution
68 |
69 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
70 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-delegated-routing-example",
3 | "version": "0.0.0",
4 | "description": "How to use other libp2p nodes to perform delegated routing",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-examples/tree/main/examples/js-libp2p-example-delegated-routing#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "start": "vite",
17 | "build": "vite build",
18 | "server": "node ./server.js",
19 | "test:firefox": "npm run build && playwright test --browser=firefox test",
20 | "test:chrome": "npm run build && playwright test test",
21 | "test": "npm run build && test-browser-example test"
22 | },
23 | "dependencies": {
24 | "@helia/delegated-routing-v1-http-api-client": "^4.0.0",
25 | "@helia/delegated-routing-v1-http-api-server": "^4.0.0",
26 | "libp2p": "^2.0.0",
27 | "react": "^18.3.1",
28 | "react-dom": "^18.3.1",
29 | "vite": "^6.0.3"
30 | },
31 | "devDependencies": {
32 | "@libp2p/peer-id": "^5.0.4",
33 | "eslint-config-ipfs": "^7.0.2",
34 | "helia": "^5.0.0",
35 | "test-ipfs-example": "^1.0.0"
36 | },
37 | "private": true
38 | }
39 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/server.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import { createDelegatedRoutingV1HttpApiServer } from '@helia/delegated-routing-v1-http-api-server'
3 | import { createHelia } from 'helia'
4 |
5 | const helia = await createHelia()
6 |
7 | const fastify = await createDelegatedRoutingV1HttpApiServer(helia, {
8 | listen: {
9 | host: '127.0.0.1',
10 | port: 9832,
11 | listenTextResolver: (address) => { return `server is listening at ${address}` }
12 | }
13 | })
14 |
15 | console.info(`Server listening on http://${fastify.server.address().address}:${fastify.server.address().port}`)
16 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/src/App.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | // eslint-disable-next-line
3 | 'use strict'
4 |
5 | import { peerIdFromString } from '@libp2p/peer-id'
6 | import { CID } from 'multiformats/cid'
7 | import React from 'react'
8 | import { configureLibp2p } from './libp2p.js'
9 |
10 | const Component = React.Component
11 |
12 | class App extends Component {
13 | constructor (props) {
14 | super(props)
15 | this.state = {
16 | // This hash is the 'hello world' string
17 | hash: 'bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e',
18 | // This peer is one of the Bootstrap nodes for Helia
19 | peer: 'QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
20 | isLoading: 0
21 | }
22 | this.peerInterval = null
23 |
24 | this.handleHashChange = this.handleHashChange.bind(this)
25 | this.handleHashSubmit = this.handleHashSubmit.bind(this)
26 | this.handlePeerChange = this.handlePeerChange.bind(this)
27 | this.handlePeerSubmit = this.handlePeerSubmit.bind(this)
28 | }
29 |
30 | handleHashChange (event) {
31 | this.setState({
32 | hash: event.target.value
33 | })
34 | }
35 |
36 | handlePeerChange (event) {
37 | this.setState({
38 | peer: event.target.value
39 | })
40 | }
41 |
42 | async handleHashSubmit (event) {
43 | event.preventDefault()
44 | this.setState({
45 | isLoading: this.state.isLoading + 1
46 | })
47 |
48 | const providers = []
49 |
50 | for await (const provider of this.libp2p.contentRouting.findProviders(CID.parse(this.state.hash))) {
51 | providers.push(provider)
52 |
53 | this.setState({
54 | response: JSON.stringify(providers, null, 2),
55 | isLoading: this.state.isLoading - 1
56 | })
57 | }
58 |
59 | this.setState({
60 | response: JSON.stringify(providers, null, 2),
61 | isLoading: this.state.isLoading - 1
62 | })
63 | }
64 |
65 | async handlePeerSubmit (event) {
66 | event.preventDefault()
67 | this.setState({
68 | isLoading: this.state.isLoading + 1
69 | })
70 |
71 | try {
72 | const peerInfo = await this.libp2p.peerRouting.findPeer(peerIdFromString(this.state.peer))
73 |
74 | this.setState({
75 | response: JSON.stringify(peerInfo, null, 2),
76 | isLoading: this.state.isLoading - 1
77 | })
78 | } catch (err) {
79 | this.setState({
80 | response: `Error finding peer: ${err.message}`,
81 | isLoading: this.state.isLoading - 1
82 | })
83 | }
84 | }
85 |
86 | async componentDidMount () {
87 | window.libp2p = this.libp2p = await configureLibp2p()
88 | }
89 |
90 | render () {
91 | return (
92 |
93 |
94 | Delegated Routing
95 |
96 |
112 |
0 ? 'loading' : '', 'loader'].join(' ')}>
113 |
114 |
115 |
116 |
117 | {this.state.response}
118 |
119 |
120 |
121 | )
122 | }
123 | }
124 |
125 | export default App
126 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Delegated Routing
8 |
9 |
10 |
11 |
12 |
13 | Delegated Routing
14 |
15 |
31 |
34 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/src/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { createDelegatedRoutingV1HttpApiClient } from '@helia/delegated-routing-v1-http-api-client'
4 | import { peerIdFromString } from '@libp2p/peer-id'
5 | import { createLibp2p } from 'libp2p'
6 | import { CID } from 'multiformats/cid'
7 |
8 | const DOM = {
9 | findProvidersInput: () => document.getElementById('find-providers-input'),
10 | findProvidersButton: () => document.getElementById('find-providers-button'),
11 |
12 | findPeerInput: () => document.getElementById('find-peer-input'),
13 | findPeerButton: () => document.getElementById('find-peer-button'),
14 |
15 | loadingNotificationElement: () => document.getElementById('loading-notification'),
16 |
17 | output: () => document.getElementById('output')
18 | }
19 |
20 | const libp2p = await createLibp2p({
21 | services: {
22 | delegatedRouting: () => createDelegatedRoutingV1HttpApiClient('http://127.0.0.1:9832')
23 | }
24 | })
25 |
26 | // find providers
27 | DOM.findProvidersButton().onclick = async (event) => {
28 | event.preventDefault()
29 | DOM.loadingNotificationElement().className = 'loading'
30 |
31 | try {
32 | const cid = CID.parse(DOM.findProvidersInput().value)
33 | const providers = []
34 | DOM.output().innerText = ''
35 |
36 | for await (const provider of libp2p.contentRouting.findProviders(cid)) {
37 | providers.push(provider)
38 |
39 | DOM.output().innerText = JSON.stringify(providers, null, 2)
40 | }
41 | } finally {
42 | DOM.loadingNotificationElement().className = ''
43 | }
44 | }
45 |
46 | // find peer
47 | DOM.findPeerButton().onclick = async (event) => {
48 | event.preventDefault()
49 | DOM.loadingNotificationElement().className = 'loading'
50 |
51 | try {
52 | const peerId = peerIdFromString(DOM.findPeerInput().value)
53 | DOM.output().innerText = ''
54 | const peerInfo = await libp2p.peerRouting.findPeer(peerId)
55 |
56 | DOM.output().innerText = JSON.stringify(peerInfo, null, 2)
57 | } finally {
58 | DOM.loadingNotificationElement().className = ''
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/src/libp2p.js:
--------------------------------------------------------------------------------
1 | import { createDelegatedRoutingV1HttpApiClient } from '@helia/delegated-routing-v1-http-api-client'
2 | import { createLibp2p } from 'libp2p'
3 |
4 | /**
5 | * Creates a basic libp2p node - it will only perform peer/content routing via
6 | * the configured delegated routing v1 http api client
7 | */
8 | export async function configureLibp2p () {
9 | return await createLibp2p({
10 | services: {
11 | delegatedRouting: () => createDelegatedRoutingV1HttpApiClient('http://127.0.0.1:9832')
12 | }
13 | })
14 | }
15 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/src/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 | section * {
8 | margin: 10px;
9 | }
10 |
11 | header {
12 | background-color: #222;
13 | height: 150px;
14 | padding: 20px;
15 | color: white;
16 | }
17 |
18 | .center {
19 | text-align: center;
20 | }
21 |
22 | pre {
23 | background-color: bisque;
24 | min-height: 100px;
25 | margin: 0px;
26 | padding: 10px;
27 | }
28 |
29 | .loader {
30 | text-align: center;
31 | height: 64px;
32 | margin-bottom: -64px;
33 | }
34 |
35 | .loading .lds-ripple {
36 | display: inline-block;
37 | position: relative;
38 | width: 64px;
39 | height: 64px;
40 | }
41 | .loading .lds-ripple div {
42 | position: absolute;
43 | border: 4px solid #000;
44 | opacity: 1;
45 | border-radius: 50%;
46 | animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
47 | margin: auto;
48 | }
49 | .loading .lds-ripple div:nth-child(2) {
50 | animation-delay: -0.5s;
51 | }
52 | @keyframes lds-ripple {
53 | 0% {
54 | top: 28px;
55 | left: 28px;
56 | width: 0;
57 | height: 0;
58 | opacity: 1;
59 | }
60 | 100% {
61 | top: -1px;
62 | left: -1px;
63 | width: 58px;
64 | height: 58px;
65 | opacity: 0;
66 | }
67 | }
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/test/index.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import { createDelegatedRoutingV1HttpApiServer } from '@helia/delegated-routing-v1-http-api-server'
3 | import { peerIdFromString } from '@libp2p/peer-id'
4 | import { createHelia, libp2pDefaults } from 'helia'
5 | import { setup, expect } from 'test-ipfs-example/browser'
6 |
7 | // Setup
8 | const test = setup()
9 |
10 | // DOM
11 | const findProvidersInput = '#find-providers-input'
12 | const findProvidersBtn = '#find-providers-button'
13 | const findPeerInput = '#find-peer-input'
14 | const findPeerBtn = '#find-peer-button'
15 | const output = '#output'
16 |
17 | let url
18 |
19 | // start a libp2p node to delegate to
20 | async function spawnServer () {
21 | const libp2p = libp2pDefaults()
22 |
23 | if (process.env.CI != null) {
24 | // do not use UPnP service in CI
25 | delete libp2p.services.upnp
26 | }
27 |
28 | const helia = await createHelia({
29 | routers: [{
30 | // dummy router that always finds providers
31 | findProviders: async function * () {
32 | yield {
33 | id: peerIdFromString('QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN'),
34 | multiaddrs: [],
35 | protocols: []
36 | }
37 | },
38 | findPeer: async function () {
39 | return {
40 | id: peerIdFromString('QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN'),
41 | multiaddrs: []
42 | }
43 | }
44 | }],
45 | libp2p
46 | })
47 | const fastify = await createDelegatedRoutingV1HttpApiServer(helia, {
48 | listen: {
49 | host: '127.0.0.1',
50 | port: 9832,
51 | listenTextResolver: (address) => { return `server is listening at ${address}` }
52 | }
53 | })
54 |
55 | return { helia, fastify }
56 | }
57 |
58 | test.describe('delegated routing example:', () => {
59 | let helia
60 | let fastify
61 |
62 | // eslint-disable-next-line no-empty-pattern
63 | test.beforeAll(async ({ servers }, testInfo) => {
64 | testInfo.setTimeout(5 * 60_000)
65 | const r = await spawnServer()
66 | helia = r.helia
67 | fastify = r.fastify
68 | url = servers[0].url
69 | }, {})
70 |
71 | test.afterAll(async () => {
72 | await fastify?.close()
73 | await helia?.stop()
74 | })
75 |
76 | test.beforeEach(async ({ page }) => {
77 | await page.goto(url)
78 | })
79 |
80 | test('should find providers using the delegate', async ({ page, context }) => {
81 | // add the empty directory CID to the input field and submit
82 | await page.fill(findProvidersInput, 'bafybeiczsscdsbs7ffqz55asqdf3smv6klcw3gofszvwlyarci47bgf354')
83 | await page.click(findProvidersBtn)
84 |
85 | const outputLocator = page.locator(output)
86 | await expect(outputLocator).toContainText('[')
87 | })
88 |
89 | test('should find peer using the delegate', async ({ page, context }) => {
90 | // add the relay multiaddr to the input field and submit
91 | await page.fill(findPeerInput, 'QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN')
92 | await page.click(findPeerBtn)
93 |
94 | const outputLocator = page.locator(output)
95 | await expect(outputLocator).toContainText('multiaddrs":')
96 | })
97 | })
98 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-delegated-routing/vite.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | build: {
3 | target: 'es2022',
4 | outDir: '../dist',
5 | emptyOutDir: true
6 | },
7 | optimizeDeps: {
8 | esbuildOptions: { target: 'es2022', supported: { bigint: true } }
9 | },
10 | server: {
11 | open: true
12 | },
13 | root: './src'
14 | }
15 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/1-dht.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { bootstrap } from '@libp2p/bootstrap'
6 | import { identify } from '@libp2p/identify'
7 | import { kadDHT, removePublicAddressesMapper } from '@libp2p/kad-dht'
8 | import { ping } from '@libp2p/ping'
9 | import { tcp } from '@libp2p/tcp'
10 | import { createLibp2p } from 'libp2p'
11 | import bootstrappers from './bootstrappers.js'
12 |
13 | const node = await createLibp2p({
14 | addresses: {
15 | listen: ['/ip4/0.0.0.0/tcp/0']
16 | },
17 | transports: [tcp()],
18 | streamMuxers: [yamux()],
19 | connectionEncrypters: [noise()],
20 | peerDiscovery: [
21 | bootstrap({
22 | list: bootstrappers
23 | })
24 | ],
25 | services: {
26 | kadDHT: kadDHT({
27 | protocol: '/ipfs/lan/kad/1.0.0',
28 | peerInfoMapper: removePublicAddressesMapper,
29 | clientMode: false
30 | }),
31 | identify: identify(),
32 | ping: ping()
33 | }
34 | })
35 |
36 | node.addEventListener('peer:connect', (evt) => {
37 | const peerId = evt.detail
38 | console.log('Connection established to:', peerId.toString()) // Emitted when a peer has been found
39 | })
40 |
41 | node.addEventListener('peer:discovery', (evt) => {
42 | const peerInfo = evt.detail
43 |
44 | console.log('Discovered:', peerInfo.id.toString())
45 | })
46 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/2-mdns.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { mdns } from '@libp2p/mdns'
6 | import { tcp } from '@libp2p/tcp'
7 | import { createLibp2p } from 'libp2p'
8 |
9 | const createNode = async () => {
10 | const node = await createLibp2p({
11 | addresses: {
12 | listen: ['/ip4/0.0.0.0/tcp/0']
13 | },
14 | transports: [
15 | tcp()
16 | ],
17 | streamMuxers: [
18 | yamux()
19 | ],
20 | connectionEncrypters: [
21 | noise()
22 | ],
23 | peerDiscovery: [
24 | mdns({
25 | interval: 20e3
26 | })
27 | ]
28 | })
29 |
30 | return node
31 | }
32 |
33 | ;(async () => {
34 | const [node1, node2] = await Promise.all([
35 | createNode(),
36 | createNode()
37 | ])
38 |
39 | node1.addEventListener('peer:discovery', (evt) => console.log('Discovered:', evt.detail.id.toString()))
40 | node2.addEventListener('peer:discovery', (evt) => console.log('Discovered:', evt.detail.id.toString()))
41 | })()
42 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/3-pubsub.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { gossipsub } from '@chainsafe/libp2p-gossipsub'
4 | import { noise } from '@chainsafe/libp2p-noise'
5 | import { yamux } from '@chainsafe/libp2p-yamux'
6 | import { bootstrap } from '@libp2p/bootstrap'
7 | import { identify } from '@libp2p/identify'
8 | import { pubsubPeerDiscovery } from '@libp2p/pubsub-peer-discovery'
9 | import { tcp } from '@libp2p/tcp'
10 | import { createLibp2p } from 'libp2p'
11 |
12 | const createNode = async (bootstrappers = []) => {
13 | const config = {
14 | addresses: {
15 | listen: ['/ip4/0.0.0.0/tcp/0']
16 | },
17 | transports: [tcp()],
18 | streamMuxers: [yamux()],
19 | connectionEncrypters: [noise()],
20 | peerDiscovery: [
21 | pubsubPeerDiscovery({
22 | interval: 1000
23 | })
24 | ],
25 | services: {
26 | pubsub: gossipsub(),
27 | identify: identify()
28 | }
29 | }
30 |
31 | if (bootstrappers.length > 0) {
32 | config.peerDiscovery.push(bootstrap({
33 | list: bootstrappers
34 | }))
35 | }
36 |
37 | return await createLibp2p(config)
38 | }
39 |
40 | const bootstrapper = await createNode([])
41 |
42 | console.log(`libp2p bootstrapper started with id: ${bootstrapper.peerId.toString()}`)
43 |
44 | const bootstrapperMultiaddrs = bootstrapper.getMultiaddrs().map((m) => m.toString())
45 |
46 | const [node1, node2] = await Promise.all([
47 | createNode(bootstrapperMultiaddrs),
48 | createNode(bootstrapperMultiaddrs)
49 | ])
50 |
51 | node1.addEventListener('peer:discovery', (evt) => {
52 | const peer = evt.detail
53 | console.log(`Peer ${node1.peerId.toString()} discovered: ${peer.id.toString()}`)
54 | })
55 | node2.addEventListener('peer:discovery', (evt) => {
56 | const peer = evt.detail
57 | console.log(`Peer ${node2.peerId.toString()} discovered: ${peer.id.toString()}`)
58 | })
59 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/bootstrappers.js:
--------------------------------------------------------------------------------
1 | // Find this list at: https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs-core-config/src/config.js
2 | export default [
3 | '/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
4 | '/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
5 | '/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
6 | '/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
7 | '/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
8 | '/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
9 | ]
10 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-discovery-mechanisms",
3 | "version": "0.0.0",
4 | "description": "How to configure peer discovery mechanisms",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-examples/tree/main/examples/js-libp2p-example-discovery-mechanisms#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "test": "test-node-example test/*"
17 | },
18 | "dependencies": {
19 | "@chainsafe/libp2p-gossipsub": "^14.1.0",
20 | "@chainsafe/libp2p-noise": "^16.0.0",
21 | "@chainsafe/libp2p-yamux": "^7.0.0",
22 | "@libp2p/bootstrap": "^11.0.0",
23 | "@libp2p/circuit-relay-v2": "^3.0.0",
24 | "@libp2p/identify": "^3.0.0",
25 | "@libp2p/kad-dht": "^15.0.0",
26 | "@libp2p/mdns": "^11.0.0",
27 | "@libp2p/ping": "^2.0.27",
28 | "@libp2p/pubsub-peer-discovery": "^11.0.0",
29 | "@libp2p/tcp": "^10.0.0",
30 | "libp2p": "^2.0.0"
31 | },
32 | "devDependencies": {
33 | "execa": "^9.2.0",
34 | "p-wait-for": "^5.0.2",
35 | "test-ipfs-example": "^1.1.0",
36 | "uint8arrays": "^5.1.0"
37 | },
38 | "private": true
39 | }
40 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/test/test-1-dht.spec.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | process.stdout.write('1.js\n')
8 |
9 | await waitForOutput('Connection established to:', 'node', [path.join(__dirname, '..', '1-dht.js')], {
10 | cwd: __dirname
11 | })
12 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/test/test-2-mdns.spec.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { execa } from 'execa'
4 | import pWaitFor from 'p-wait-for'
5 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
6 |
7 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
8 |
9 | let discoveredNodes = 0
10 |
11 | process.stdout.write('2.js\n')
12 |
13 | const proc = execa('node', [path.join(__dirname, '..', '2-mdns.js')], {
14 | cwd: path.resolve(__dirname),
15 | all: true
16 | })
17 |
18 | proc.all.on('data', async (data) => {
19 | process.stdout.write(data)
20 | const str = uint8ArrayToString(data)
21 |
22 | str.split('\n').forEach(line => {
23 | if (line.includes('Discovered:')) {
24 | discoveredNodes++
25 | }
26 | })
27 | })
28 |
29 | await pWaitFor(() => discoveredNodes > 1, 600000)
30 |
31 | process.exit(0)
32 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-discovery-mechanisms/test/test-3-pubsub.spec.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { execa } from 'execa'
4 | import pWaitFor from 'p-wait-for'
5 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
6 |
7 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
8 |
9 | const discoveredPeers = []
10 |
11 | process.stdout.write('3.js\n')
12 |
13 | const proc = execa('node', [path.join(__dirname, '..', '3-pubsub.js')], {
14 | cwd: path.resolve(__dirname),
15 | all: true
16 | })
17 |
18 | proc.all.on('data', async (data) => {
19 | process.stdout.write(data)
20 | const str = uint8ArrayToString(data)
21 | const discoveredPeersRegex = /Peer\s+(?[^\s]+)\s+discovered:\s+(?[^\s]+)/
22 | str.split('\n').forEach(line => {
23 | const peers = line.match(discoveredPeersRegex)
24 | if (peers != null) {
25 | // sort so we don't count reversed pair twice
26 | const match = [peers.groups.Peer1, peers.groups.Peer2].sort().join(',')
27 | if (!discoveredPeers.includes(match)) {
28 | discoveredPeers.push(match)
29 | }
30 | }
31 | })
32 | })
33 |
34 | await pWaitFor(() => discoveredPeers.length > 2, 600000)
35 |
36 | process.exit(0)
37 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/1.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { identify, identifyPush } from '@libp2p/identify'
6 | import { kadDHT, removePublicAddressesMapper } from '@libp2p/kad-dht'
7 | import { ping } from '@libp2p/ping'
8 | import { tcp } from '@libp2p/tcp'
9 | import { createLibp2p } from 'libp2p'
10 |
11 | const createNode = async () => {
12 | const node = await createLibp2p({
13 | addresses: {
14 | listen: ['/ip4/0.0.0.0/tcp/0']
15 | },
16 | transports: [tcp()],
17 | streamMuxers: [yamux()],
18 | connectionEncrypters: [noise()],
19 | services: {
20 | // configure Kad-DHT to run on the local network
21 | dht: kadDHT({
22 | protocol: '/ipfs/lan/kad/1.0.0',
23 | peerInfoMapper: removePublicAddressesMapper,
24 | clientMode: false
25 | }),
26 | identify: identify(),
27 | identifyPush: identifyPush(),
28 | ping: ping()
29 | }
30 | })
31 |
32 | return node
33 | }
34 |
35 | const [node1, node2, node3] = await Promise.all([
36 | createNode(),
37 | createNode(),
38 | createNode()
39 | ])
40 |
41 | // Connect the nodes 1 -> 2 -> 3
42 | await Promise.all([
43 | node1.dial(node2.getMultiaddrs()),
44 | node2.dial(node3.getMultiaddrs())
45 | ])
46 |
47 | // find peer 3 from peer 1 (there is no direct connection)
48 | const peer = await node1.peerRouting.findPeer(node3.peerId)
49 |
50 | console.log('Found it, multiaddrs are:')
51 | peer.multiaddrs.forEach((ma) => console.log(ma.toString()))
52 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/2.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { identify, identifyPush } from '@libp2p/identify'
6 | import { kadDHT, removePublicAddressesMapper } from '@libp2p/kad-dht'
7 | import { ping } from '@libp2p/ping'
8 | import { tcp } from '@libp2p/tcp'
9 | import all from 'it-all'
10 | import { createLibp2p } from 'libp2p'
11 | import { CID } from 'multiformats/cid'
12 |
13 | const createNode = async () => {
14 | const node = await createLibp2p({
15 | addresses: {
16 | listen: ['/ip4/0.0.0.0/tcp/0']
17 | },
18 | transports: [tcp()],
19 | streamMuxers: [yamux()],
20 | connectionEncrypters: [noise()],
21 | services: {
22 | dht: kadDHT({
23 | protocol: '/ipfs/lan/kad/1.0.0',
24 | peerInfoMapper: removePublicAddressesMapper,
25 | clientMode: false
26 | }),
27 | identify: identify(),
28 | identifyPush: identifyPush(),
29 | ping: ping()
30 | }
31 | })
32 |
33 | return node
34 | }
35 |
36 | const [node1, node2, node3] = await Promise.all([
37 | createNode(),
38 | createNode(),
39 | createNode()
40 | ])
41 |
42 | await Promise.all([
43 | node1.dial(node2.getMultiaddrs()),
44 | node2.dial(node3.getMultiaddrs())
45 | ])
46 |
47 | const cid = CID.parse('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL')
48 | await node1.contentRouting.provide(cid)
49 |
50 | console.log('Node %s is providing %s', node1.peerId.toString(), cid.toString())
51 |
52 | const providers = await all(node3.contentRouting.findProviders(cid, { timeout: 3000 }))
53 |
54 | console.log('Found provider:', providers[0].id.toString())
55 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-peer-and-content-routing",
3 | "version": "0.0.0",
4 | "description": "How to use peer and content routing",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-examples/tree/master/examples/js-libp2p-example-peer-and-content-routing#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "lint": "aegir lint",
17 | "test": "test-node-example test/*"
18 | },
19 | "dependencies": {
20 | "@chainsafe/libp2p-noise": "^16.0.0",
21 | "@chainsafe/libp2p-yamux": "^7.0.0",
22 | "@libp2p/identify": "^3.0.1",
23 | "@libp2p/kad-dht": "^15.0.0",
24 | "@libp2p/ping": "^2.0.27",
25 | "@libp2p/tcp": "^10.0.0",
26 | "it-all": "^3.0.2",
27 | "libp2p": "^2.0.0",
28 | "multiformats": "^13.1.1"
29 | },
30 | "devDependencies": {
31 | "test-ipfs-example": "^1.1.0"
32 | },
33 | "private": true
34 | }
35 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/test/index.js:
--------------------------------------------------------------------------------
1 | import { test as test1 } from './test-1.js'
2 | import { test as test2 } from './test-2.js'
3 |
4 | await test1()
5 | await test2()
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/test/test-1.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('1.js\n')
9 |
10 | await waitForOutput('Found it, multiaddrs are:', 'node', [path.join(__dirname, '../1.js')], {
11 | cwd: __dirname
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-peer-and-content-routing/test/test-2.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('2.js\n')
9 |
10 | await waitForOutput('Found provider:', 'node', [path.join(__dirname, '../2.js')], {
11 | cwd: __dirname
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pnet/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pnet/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pnet/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pnet/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pnet/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pnet/README.md:
--------------------------------------------------------------------------------
1 | # @libp2p/example-pnet
2 |
3 | [](http://libp2p.io/)
4 | [](https://discuss.libp2p.io)
5 | [](https://codecov.io/gh/libp2p/js-libp2p-examples)
6 | [](https://github.com/libp2p/js-libp2p-examples/actions/workflows/ci.yml?query=branch%3Amain)
7 |
8 | > How to configure a libp2p private network
9 |
10 | libp2p networks allow any peer to connect to any other peer and to communicate
11 | with them via protocol streams.
12 |
13 | What if you only want to allow a certain subset of peers to connect to you? It's
14 | possible to use a pre-shared key to create a private network on top of the
15 | public libp2p network using the `@libp2p/pnet` module.
16 |
17 | ## Setup
18 |
19 | 1. Install the modules in the libp2p root directory, `npm install` and`npm run build`.
20 |
21 | ## Run
22 |
23 | Running the example will cause two nodes with the same swarm key to be started
24 | and exchange basic information.
25 |
26 | ```
27 | node index.js
28 | ```
29 |
30 | ### Using different keys
31 |
32 | This example includes `TASK` comments that can be used to try the example with
33 | different swarm keys. This will allow you to see how nodes will fail to connect
34 | if they are on different private networks and try to connect to one another.
35 |
36 | To change the swarm key of one of the nodes, look through `index.js` for
37 | comments starting with `TASK` to indicate where lines are that pertain to
38 | changing the swarm key of node 2.
39 |
40 | ### Exploring the repos
41 |
42 | Once you've run the example you can take a look at the repos in the `./tmp`
43 | directory to see how they differ, including the swarm keys. You should see a
44 | `swarm.key` file in each of the repos and when the nodes are on the same private
45 | network this contents of the `swarm.key` files should be the same.
46 |
47 | ## Need help?
48 |
49 | - Read the [js-libp2p documentation](https://github.com/libp2p/js-libp2p/tree/main/doc)
50 | - Check out the [js-libp2p API docs](https://libp2p.github.io/js-libp2p/)
51 | - Check out the [general libp2p documentation](https://docs.libp2p.io) for tips, how-tos and more
52 | - Read the [libp2p specs](https://github.com/libp2p/specs)
53 | - Ask a question on the [js-libp2p discussion board](https://github.com/libp2p/js-libp2p/discussions)
54 |
55 | ## License
56 |
57 | Licensed under either of
58 |
59 | - Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / )
60 | - MIT ([LICENSE-MIT](LICENSE-MIT) / )
61 |
62 | ## Contribution
63 |
64 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
65 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pnet/index.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: ["off"] */
2 |
3 | import { generateKey } from '@libp2p/pnet'
4 | import { pipe } from 'it-pipe'
5 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
6 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
7 | import { privateLibp2pNode } from './libp2p-node.js'
8 |
9 | // Create a Uint8Array and write the swarm key to it
10 | const swarmKey = new Uint8Array(95)
11 | generateKey(swarmKey)
12 |
13 | // This key is for testing a different key not working
14 | const otherSwarmKey = new Uint8Array(95)
15 | generateKey(otherSwarmKey)
16 |
17 | const node1 = await privateLibp2pNode(swarmKey)
18 |
19 | // TASK: switch the commented out line below so we're using a different key, to see the nodes fail to connect
20 | const node2 = await privateLibp2pNode(swarmKey)
21 | // const node2 = await privateLibp2pNode(otherSwarmKey)
22 |
23 | console.log('nodes started...')
24 |
25 | // connect node1 to node2
26 | await node1.dial(node2.getMultiaddrs())
27 |
28 | node2.handle('/private', ({ stream }) => {
29 | pipe(
30 | stream,
31 | async function (source) {
32 | for await (const msg of source) {
33 | console.log(uint8ArrayToString(msg.subarray()))
34 | }
35 | }
36 | )
37 | })
38 |
39 | const stream = await node1.dialProtocol(node2.peerId, '/private')
40 |
41 | await pipe(
42 | [uint8ArrayFromString('This message is sent on a private network')],
43 | stream
44 | )
45 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pnet/libp2p-node.js:
--------------------------------------------------------------------------------
1 | import { noise } from '@chainsafe/libp2p-noise'
2 | import { yamux } from '@chainsafe/libp2p-yamux'
3 | import { preSharedKey } from '@libp2p/pnet'
4 | import { tcp } from '@libp2p/tcp'
5 | import { createLibp2p } from 'libp2p'
6 |
7 | /**
8 | * privateLibp2pNode returns a libp2p node function that will use the swarm
9 | * key with the given `swarmKey` to create the Protector
10 | *
11 | * @param {any} swarmKey
12 | */
13 | export async function privateLibp2pNode (swarmKey) {
14 | const node = await createLibp2p({
15 | addresses: {
16 | listen: ['/ip4/0.0.0.0/tcp/0']
17 | },
18 | transports: [tcp()], // We're only using the TCP transport for this example
19 | streamMuxers: [yamux()], // We're only using yamux muxing
20 | // Let's make sure to use identifying crypto in our pnet since the protector
21 | // doesn't care about node identity, and only the presence of private keys
22 | connectionEncrypters: [noise()],
23 | // Leave peer discovery empty, we don't want to find peers. We could omit
24 | // the property, but it's being left in for explicit readability.
25 | // We should explicitly dial pnet peers, or use a custom discovery service
26 | // for finding nodes in our pnet
27 | peerDiscovery: [],
28 | connectionProtector: preSharedKey({
29 | psk: swarmKey
30 | })
31 | })
32 |
33 | return node
34 | }
35 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pnet/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-pnet",
3 | "version": "0.0.0",
4 | "description": "How to configure a libp2p private network",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-examples/tree/master/examples/js-libp2p-example-pnet#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "test": "test-node-example test/*"
17 | },
18 | "dependencies": {
19 | "@chainsafe/libp2p-noise": "^16.0.0",
20 | "@chainsafe/libp2p-yamux": "^7.0.0",
21 | "@libp2p/pnet": "^2.0.1",
22 | "@libp2p/tcp": "^10.0.0",
23 | "it-pipe": "^3.0.1",
24 | "libp2p": "^2.0.0",
25 | "uint8arrays": "^5.1.0"
26 | },
27 | "devDependencies": {
28 | "test-ipfs-example": "^1.1.0"
29 | },
30 | "private": true
31 | }
32 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pnet/test/index.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | await waitForOutput('This message is sent on a private network', 'node', [path.join(__dirname, '../index.js')], {
8 | cwd: __dirname
9 | })
10 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/1.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { tcp } from '@libp2p/tcp'
6 | import { pipe } from 'it-pipe'
7 | import { createLibp2p } from 'libp2p'
8 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
9 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
10 |
11 | const createNode = async () => {
12 | const node = await createLibp2p({
13 | addresses: {
14 | listen: ['/ip4/0.0.0.0/tcp/0']
15 | },
16 | transports: [tcp()],
17 | streamMuxers: [yamux()],
18 | connectionEncrypters: [noise()]
19 | })
20 |
21 | return node
22 | }
23 |
24 | const [node1, node2] = await Promise.all([
25 | createNode(),
26 | createNode()
27 | ])
28 |
29 | // exact matching
30 | node2.handle('/your-protocol', ({ stream }) => {
31 | pipe(
32 | stream,
33 | async function (source) {
34 | for await (const msg of source) {
35 | console.log(uint8ArrayToString(msg.subarray()))
36 | }
37 | }
38 | )
39 | })
40 |
41 | // multiple protocols
42 | /*
43 | node2.handle(['/another-protocol/1.0.0', '/another-protocol/2.0.0'], ({ protocol, stream }) => {
44 | if (protocol === '/another-protocol/2.0.0') {
45 | // handle backwards compatibility
46 | }
47 |
48 | pipe(
49 | stream,
50 | async function (source) {
51 | for await (const msg of source) {
52 | console.log(uint8ArrayToString(msg))
53 | }
54 | }
55 | )
56 | })
57 | */
58 |
59 | const stream = await node1.dialProtocol(node2.getMultiaddrs(), ['/your-protocol'])
60 | await pipe(
61 | [uint8ArrayFromString('my own protocol, wow!')],
62 | stream
63 | )
64 |
65 | /*
66 | const stream = node1.dialProtocol(node2.peerId, ['/another-protocol/1.0.0'])
67 |
68 | await pipe(
69 | ['my own protocol, wow!'],
70 | stream
71 | )
72 | */
73 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/2.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { tcp } from '@libp2p/tcp'
6 | import { pipe } from 'it-pipe'
7 | import { createLibp2p } from 'libp2p'
8 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
9 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
10 |
11 | const createNode = async () => {
12 | const node = await createLibp2p({
13 | addresses: {
14 | listen: ['/ip4/0.0.0.0/tcp/0']
15 | },
16 | transports: [tcp()],
17 | streamMuxers: [yamux()],
18 | connectionEncrypters: [noise()]
19 | })
20 |
21 | return node
22 | }
23 |
24 | const [node1, node2] = await Promise.all([
25 | createNode(),
26 | createNode()
27 | ])
28 |
29 | // Add node's 2 data to the PeerStore
30 | await node1.peerStore.patch(node2.peerId, {
31 | multiaddrs: node2.getMultiaddrs()
32 | })
33 |
34 | node2.handle(['/a', '/b'], ({ protocol, stream }) => {
35 | pipe(
36 | stream,
37 | async function (source) {
38 | for await (const msg of source) {
39 | console.log(`from: ${protocol}, msg: ${uint8ArrayToString(msg.subarray())}`)
40 | }
41 | }
42 | ).finally(() => {
43 | // clean up resources
44 | stream.close()
45 | })
46 | })
47 |
48 | const stream1 = await node1.dialProtocol(node2.peerId, ['/a'])
49 | await pipe(
50 | [uint8ArrayFromString('protocol (a)')],
51 | stream1
52 | )
53 |
54 | const stream2 = await node1.dialProtocol(node2.peerId, ['/b'])
55 | await pipe(
56 | [uint8ArrayFromString('protocol (b)')],
57 | stream2
58 | )
59 |
60 | const stream3 = await node1.dialProtocol(node2.peerId, ['/b'])
61 | await pipe(
62 | [uint8ArrayFromString('another stream on protocol (b)')],
63 | stream3
64 | )
65 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/3.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { tcp } from '@libp2p/tcp'
6 | import { pipe } from 'it-pipe'
7 | import { createLibp2p } from 'libp2p'
8 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
9 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
10 |
11 | const createNode = async () => {
12 | const node = await createLibp2p({
13 | addresses: {
14 | listen: ['/ip4/0.0.0.0/tcp/0']
15 | },
16 | transports: [tcp()],
17 | streamMuxers: [yamux()],
18 | connectionEncrypters: [noise()]
19 | })
20 |
21 | return node
22 | }
23 |
24 | const [node1, node2] = await Promise.all([
25 | createNode(),
26 | createNode()
27 | ])
28 |
29 | // Add node's 2 data to the PeerStore
30 | await node1.peerStore.patch(node2.peerId, {
31 | multiaddrs: node2.getMultiaddrs()
32 | })
33 |
34 | node1.handle('/node-1', ({ stream }) => {
35 | pipe(
36 | stream,
37 | async function (source) {
38 | for await (const msg of source) {
39 | console.log(uint8ArrayToString(msg.subarray()))
40 | }
41 | }
42 | )
43 | })
44 |
45 | node2.handle('/node-2', ({ stream }) => {
46 | pipe(
47 | stream,
48 | async function (source) {
49 | for await (const msg of source) {
50 | console.log(uint8ArrayToString(msg.subarray()))
51 | }
52 | }
53 | )
54 | })
55 |
56 | const stream1 = await node1.dialProtocol(node2.peerId, ['/node-2'])
57 | await pipe(
58 | [uint8ArrayFromString('from 1 to 2')],
59 | stream1
60 | )
61 |
62 | const stream2 = await node2.dialProtocol(node1.peerId, ['/node-1'])
63 | await pipe(
64 | [uint8ArrayFromString('from 2 to 1')],
65 | stream2
66 | )
67 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-protocol-and-stream-muxing",
3 | "version": "0.0.0",
4 | "description": "How to use multiplexed protocol streams",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-examples/tree/master/examples/js-libp2p-example-protocol-and-stream-muxing#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "test": "test-node-example test/*"
17 | },
18 | "dependencies": {
19 | "@chainsafe/libp2p-noise": "^16.0.0",
20 | "@chainsafe/libp2p-yamux": "^7.0.0",
21 | "@libp2p/tcp": "^10.0.0",
22 | "it-pipe": "^3.0.1",
23 | "libp2p": "^2.0.0",
24 | "uint8arrays": "^5.1.0"
25 | },
26 | "devDependencies": {
27 | "test-ipfs-example": "^1.1.0"
28 | },
29 | "private": true
30 | }
31 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/test/test-1.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('1.js\n')
9 |
10 | await waitForOutput('my own protocol, wow!', 'node', [path.join(__dirname, '../1.js')], {
11 | cwd: __dirname
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/test/test-2.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('2.js\n')
9 |
10 | await waitForOutput('another stream on protocol (b)', 'node', [path.join(__dirname, '../2.js')], {
11 | cwd: __dirname
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/test/test-3.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('3.js\n')
9 |
10 | await waitForOutput('from 2 to 1', 'node', [path.join(__dirname, '../3.js')], {
11 | cwd: __dirname
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-protocol-and-stream-muxing/test/test.js:
--------------------------------------------------------------------------------
1 | import { test as test1 } from './test-1.js'
2 | import { test as test2 } from './test-2.js'
3 | import { test as test3 } from './test-3.js'
4 |
5 | await test1()
6 | await test2()
7 | await test3()
8 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/1.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { gossipsub } from '@chainsafe/libp2p-gossipsub'
4 | import { noise } from '@chainsafe/libp2p-noise'
5 | import { yamux } from '@chainsafe/libp2p-yamux'
6 | import { identify, identifyPush } from '@libp2p/identify'
7 | import { tcp } from '@libp2p/tcp'
8 | import { createLibp2p } from 'libp2p'
9 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
10 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
11 |
12 | const createNode = async () => {
13 | const node = await createLibp2p({
14 | addresses: {
15 | listen: ['/ip4/0.0.0.0/tcp/0']
16 | },
17 | transports: [tcp()],
18 | streamMuxers: [yamux()],
19 | connectionEncrypters: [noise()],
20 | services: {
21 | pubsub: gossipsub(),
22 | identify: identify(),
23 | identifyPush: identifyPush()
24 | }
25 | })
26 |
27 | return node
28 | }
29 |
30 | const topic = 'news'
31 |
32 | const [node1, node2] = await Promise.all([
33 | createNode(),
34 | createNode()
35 | ])
36 |
37 | // Connect the two nodes
38 | await node1.dial(node2.getMultiaddrs())
39 |
40 | node1.services.pubsub.subscribe(topic)
41 | node1.services.pubsub.addEventListener('message', (evt) => {
42 | console.log(`node1 received: ${uint8ArrayToString(evt.detail.data)} on topic ${evt.detail.topic}`)
43 | })
44 |
45 | // Will not receive own published messages by default
46 | node2.services.pubsub.subscribe(topic)
47 | node2.services.pubsub.addEventListener('message', (evt) => {
48 | console.log(`node2 received: ${uint8ArrayToString(evt.detail.data)} on topic ${evt.detail.topic}`)
49 | })
50 |
51 | // node2 publishes "news" every second
52 | setInterval(() => {
53 | node2.services.pubsub.publish(topic, uint8ArrayFromString('Bird bird bird, bird is the word!')).catch(err => {
54 | console.error(err)
55 | })
56 | }, 1000)
57 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/2.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { gossipsub } from '@chainsafe/libp2p-gossipsub'
4 | import { noise } from '@chainsafe/libp2p-noise'
5 | import { yamux } from '@chainsafe/libp2p-yamux'
6 | import { identify, identifyPush } from '@libp2p/identify'
7 | import { tcp } from '@libp2p/tcp'
8 | import { createLibp2p } from 'libp2p'
9 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
10 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
11 |
12 | const createNode = async () => {
13 | const node = await createLibp2p({
14 | addresses: {
15 | listen: ['/ip4/0.0.0.0/tcp/0']
16 | },
17 | transports: [tcp()],
18 | streamMuxers: [yamux()],
19 | connectionEncrypters: [noise()],
20 | services: {
21 | pubsub: gossipsub(),
22 | identify: identify(),
23 | identifyPush: identifyPush()
24 | }
25 | })
26 |
27 | return node
28 | }
29 |
30 | const topic = 'fruit'
31 |
32 | const [node1, node2, node3] = await Promise.all([
33 | createNode(),
34 | createNode(),
35 | createNode()
36 | ])
37 |
38 | // connect node1 to node2 and node2 to node3
39 | await node1.dial(node2.getMultiaddrs())
40 | await node2.dial(node3.getMultiaddrs())
41 |
42 | // subscribe
43 | node1.services.pubsub.addEventListener('message', (evt) => {
44 | if (evt.detail.topic !== topic) {
45 | return
46 | }
47 |
48 | // Will not receive own published messages by default
49 | console.log(`node1 received: ${uint8ArrayToString(evt.detail.data)}`)
50 | })
51 | node1.services.pubsub.subscribe(topic)
52 |
53 | node2.services.pubsub.addEventListener('message', (evt) => {
54 | if (evt.detail.topic !== topic) {
55 | return
56 | }
57 |
58 | console.log(`node2 received: ${uint8ArrayToString(evt.detail.data)}`)
59 | })
60 | node2.services.pubsub.subscribe(topic)
61 |
62 | node3.services.pubsub.addEventListener('message', (evt) => {
63 | if (evt.detail.topic !== topic) {
64 | return
65 | }
66 |
67 | console.log(`node3 received: ${uint8ArrayToString(evt.detail.data)}`)
68 | })
69 | node3.services.pubsub.subscribe(topic)
70 |
71 | // wait for subscriptions to propagate
72 | await hasSubscription(node1, node2, topic)
73 | await hasSubscription(node2, node3, topic)
74 |
75 | const validateFruit = (msgTopic, msg) => {
76 | const fruit = uint8ArrayToString(msg.data)
77 | const validFruit = ['banana', 'apple', 'orange']
78 |
79 | return validFruit.includes(fruit) ? 'accept' : 'ignore'
80 | }
81 |
82 | // validate fruit
83 | node1.services.pubsub.topicValidators.set(topic, validateFruit)
84 | node2.services.pubsub.topicValidators.set(topic, validateFruit)
85 | node3.services.pubsub.topicValidators.set(topic, validateFruit)
86 |
87 | // node1 publishes "fruits"
88 | for (const fruit of ['banana', 'apple', 'car', 'orange']) {
89 | console.log('############## fruit ' + fruit + ' ##############')
90 | await node1.services.pubsub.publish(topic, uint8ArrayFromString(fruit))
91 | }
92 |
93 | console.log('############## all messages sent ##############')
94 |
95 | async function delay (ms) {
96 | await new Promise((resolve) => {
97 | setTimeout(() => resolve(), ms)
98 | })
99 | }
100 |
101 | // Wait for node1 to see that node2 has subscribed to the topic
102 | async function hasSubscription (node1, node2, topic) {
103 | while (true) {
104 | const subs = await node1.services.pubsub.getSubscribers(topic)
105 |
106 | if (subs.map(peer => peer.toString()).includes(node2.peerId.toString())) {
107 | return
108 | }
109 |
110 | // wait for subscriptions to propagate
111 | await delay(100)
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-pubsub",
3 | "version": "0.0.0",
4 | "description": "An example using libp2p pubsub",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-examples/tree/master/examples/js-libp2p-example-pubsub#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "files": [
16 | "src",
17 | "dist",
18 | "!dist/test",
19 | "!**/*.tsbuildinfo"
20 | ],
21 | "exports": {
22 | ".": {
23 | "types": "./dist/src/index.d.ts",
24 | "import": "./src/index.js"
25 | }
26 | },
27 | "scripts": {
28 | "test": "test-node-example test/*"
29 | },
30 | "dependencies": {
31 | "@chainsafe/libp2p-gossipsub": "^14.1.0",
32 | "@chainsafe/libp2p-noise": "^16.0.0",
33 | "@chainsafe/libp2p-yamux": "^7.0.0",
34 | "@libp2p/identify": "^3.0.1",
35 | "@libp2p/tcp": "^10.0.0",
36 | "libp2p": "^2.0.0",
37 | "uint8arrays": "^5.1.0"
38 | },
39 | "devDependencies": {
40 | "test-ipfs-example": "^1.1.0"
41 | },
42 | "private": true
43 | }
44 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/test/test-1.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('1.js\n')
9 |
10 | await waitForOutput('node1 received: Bird bird bird, bird is the word!', 'node', [path.join(__dirname, '../1.js')], {
11 | cwd: __dirname
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/test/test-2.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('2.js\n')
9 |
10 | try {
11 | await waitForOutput('node3 received: car', 'node', [path.join(__dirname, '../2.js')], {
12 | cwd: __dirname,
13 | timeout: 2000
14 | })
15 |
16 | throw new Error('Matched content when should not have')
17 | } catch (err) {
18 | if (err.message !== 'Timed out' && !err.message.includes('Did not see')) {
19 | throw err
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-pubsub/test/test.js:
--------------------------------------------------------------------------------
1 | import { test as test1 } from './test-1.js'
2 | import { test as test2 } from './test-2.js'
3 |
4 | await test1()
5 | await test2()
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/1.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { tcp } from '@libp2p/tcp'
5 | import { createLibp2p } from 'libp2p'
6 |
7 | const createNode = async () => {
8 | const node = await createLibp2p({
9 | addresses: {
10 | // To signal the addresses we want to be available, we use
11 | // the multiaddr format, a self describable address
12 | listen: [
13 | '/ip4/0.0.0.0/tcp/0'
14 | ]
15 | },
16 | transports: [
17 | tcp()
18 | ],
19 | connectionEncrypters: [
20 | noise()
21 | ]
22 | })
23 |
24 | return node
25 | }
26 |
27 | const node = await createNode()
28 |
29 | console.log('node has started')
30 | console.log('listening on:')
31 | node.getMultiaddrs().forEach((ma) => console.log(ma.toString()))
32 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/2.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { tcp } from '@libp2p/tcp'
6 | import { pipe } from 'it-pipe'
7 | import toBuffer from 'it-to-buffer'
8 | import { createLibp2p } from 'libp2p'
9 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
10 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
11 |
12 | const createNode = async () => {
13 | const node = await createLibp2p({
14 | addresses: {
15 | // To signal the addresses we want to be available, we use
16 | // the multiaddr format, a self describable address
17 | listen: ['/ip4/0.0.0.0/tcp/0']
18 | },
19 | transports: [tcp()],
20 | connectionEncrypters: [noise()],
21 | streamMuxers: [yamux()]
22 | })
23 |
24 | return node
25 | }
26 |
27 | function printAddrs (node, number) {
28 | console.log('node %s is listening on:', number)
29 | node.getMultiaddrs().forEach((ma) => console.log(ma.toString()))
30 | }
31 |
32 | const [node1, node2] = await Promise.all([
33 | createNode(),
34 | createNode()
35 | ])
36 |
37 | printAddrs(node1, '1')
38 | printAddrs(node2, '2')
39 |
40 | node2.handle('/print', async ({ stream }) => {
41 | const result = await pipe(
42 | stream,
43 | async function * (source) {
44 | for await (const list of source) {
45 | yield list.subarray()
46 | }
47 | },
48 | toBuffer
49 | )
50 | console.log(uint8ArrayToString(result))
51 | })
52 |
53 | await node1.peerStore.patch(node2.peerId, {
54 | multiaddrs: node2.getMultiaddrs()
55 | })
56 | const stream = await node1.dialProtocol(node2.peerId, '/print')
57 |
58 | await pipe(
59 | ['Hello', ' ', 'p2p', ' ', 'world', '!'].map(str => uint8ArrayFromString(str)),
60 | stream
61 | )
62 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/3.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { tcp } from '@libp2p/tcp'
6 | import { webSockets } from '@libp2p/websockets'
7 | import { pipe } from 'it-pipe'
8 | import { createLibp2p } from 'libp2p'
9 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
10 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
11 |
12 | const createNode = async (transports, addresses = []) => {
13 | if (!Array.isArray(addresses)) {
14 | addresses = [addresses]
15 | }
16 |
17 | const node = await createLibp2p({
18 | addresses: {
19 | listen: addresses
20 | },
21 | transports,
22 | connectionEncrypters: [noise()],
23 | streamMuxers: [yamux()]
24 | })
25 |
26 | return node
27 | }
28 |
29 | function printAddrs (node, number) {
30 | console.log('node %s is listening on:', number)
31 | node.getMultiaddrs().forEach((ma) => console.log(ma.toString()))
32 | }
33 |
34 | function print ({ stream }) {
35 | pipe(
36 | stream,
37 | async function (source) {
38 | for await (const msg of source) {
39 | console.log(uint8ArrayToString(msg.subarray()))
40 | }
41 | }
42 | )
43 | }
44 |
45 | const [node1, node2, node3] = await Promise.all([
46 | createNode([tcp()], '/ip4/0.0.0.0/tcp/0'),
47 | createNode([tcp(), webSockets()], ['/ip4/0.0.0.0/tcp/0', '/ip4/127.0.0.1/tcp/10000/ws']),
48 | createNode([webSockets()], '/ip4/127.0.0.1/tcp/20000/ws')
49 | ])
50 |
51 | printAddrs(node1, '1')
52 | printAddrs(node2, '2')
53 | printAddrs(node3, '3')
54 |
55 | node1.handle('/print', print)
56 | node2.handle('/print', print)
57 | node3.handle('/print', print)
58 |
59 | await node1.peerStore.patch(node2.peerId, {
60 | multiaddrs: node2.getMultiaddrs()
61 | })
62 | await node2.peerStore.patch(node3.peerId, {
63 | multiaddrs: node3.getMultiaddrs()
64 | })
65 | await node3.peerStore.patch(node1.peerId, {
66 | multiaddrs: node1.getMultiaddrs()
67 | })
68 |
69 | // node 1 (TCP) dials to node 2 (TCP+WebSockets)
70 | const stream = await node1.dialProtocol(node2.peerId, '/print')
71 | await pipe(
72 | [uint8ArrayFromString('node 1 dialed to node 2 successfully')],
73 | stream
74 | )
75 |
76 | // node 2 (TCP+WebSockets) dials to node 3 (WebSockets)
77 | const stream2 = await node2.dialProtocol(node3.peerId, '/print')
78 | await pipe(
79 | [uint8ArrayFromString('node 2 dialed to node 3 successfully')],
80 | stream2
81 | )
82 |
83 | // node 3 (listening WebSockets) can dial node 1 (TCP)
84 | try {
85 | await node3.dialProtocol(node1.peerId, '/print')
86 | } catch (err) {
87 | console.log('node 3 failed to dial to node 1 with:', err.message)
88 | }
89 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/4.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import fs from 'fs'
4 | import { noise } from '@chainsafe/libp2p-noise'
5 | import { yamux } from '@chainsafe/libp2p-yamux'
6 | import { tcp } from '@libp2p/tcp'
7 | import { webSockets } from '@libp2p/websockets'
8 | import { pipe } from 'it-pipe'
9 | import { createLibp2p } from 'libp2p'
10 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
11 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
12 |
13 | const createNode = async (addresses = []) => {
14 | if (!Array.isArray(addresses)) {
15 | addresses = [addresses]
16 | }
17 |
18 | const node = await createLibp2p({
19 | addresses: {
20 | listen: addresses
21 | },
22 | transports: [
23 | tcp(),
24 | webSockets({
25 | https: {
26 | cert: fs.readFileSync('./test_certs/cert.pem'),
27 | key: fs.readFileSync('./test_certs/key.pem')
28 | },
29 | websocket: {
30 | rejectUnauthorized: false
31 | }
32 | })
33 | ],
34 | connectionEncrypters: [noise()],
35 | streamMuxers: [yamux()]
36 | })
37 |
38 | return node
39 | }
40 |
41 | function printAddrs (node, number) {
42 | console.log('node %s is listening on:', number)
43 | node.getMultiaddrs().forEach((ma) => console.log(ma.toString()))
44 | }
45 |
46 | function print ({ stream }) {
47 | pipe(
48 | stream,
49 | async function (source) {
50 | for await (const msg of source) {
51 | console.log(uint8ArrayToString(msg.subarray()))
52 | }
53 | }
54 | )
55 | }
56 |
57 | const [node1, node2] = await Promise.all([
58 | createNode('/ip4/127.0.0.1/tcp/10000/wss'),
59 | createNode([])
60 | ])
61 |
62 | printAddrs(node1, '1')
63 | printAddrs(node2, '2')
64 |
65 | node1.handle('/print', print)
66 | node2.handle('/print', print)
67 |
68 | const targetAddr = node1.getMultiaddrs()[0]
69 |
70 | // node 2 (Secure WebSockets) dials to node 1 (Secure Websockets)
71 | const stream = await node2.dialProtocol(targetAddr, '/print')
72 | await pipe(
73 | [uint8ArrayFromString('node 2 dialed to node 1 successfully')],
74 | stream
75 | )
76 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-transports",
3 | "version": "0.0.0",
4 | "description": "An example using different types of libp2p transport",
5 | "license": "Apache-2.0 OR MIT",
6 | "homepage": "https://github.com/libp2p/js-libp2p-examples/tree/master/examples/js-libp2p-example-transports#readme",
7 | "repository": {
8 | "type": "git",
9 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
10 | },
11 | "bugs": {
12 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
13 | },
14 | "type": "module",
15 | "scripts": {
16 | "test": "test-node-example test/*"
17 | },
18 | "dependencies": {
19 | "@chainsafe/libp2p-noise": "^16.0.0",
20 | "@chainsafe/libp2p-yamux": "^7.0.0",
21 | "@libp2p/tcp": "^10.0.0",
22 | "@libp2p/websockets": "^9.1.0",
23 | "it-pipe": "^3.0.1",
24 | "it-to-buffer": "^4.0.2",
25 | "libp2p": "^2.0.0",
26 | "uint8arrays": "^5.1.0"
27 | },
28 | "devDependencies": {
29 | "test-ipfs-example": "^1.1.0"
30 | },
31 | "private": true
32 | }
33 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/test/test-1.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('1.js\n')
9 |
10 | await waitForOutput('/p2p/', 'node', [path.join(__dirname, '../1.js')], {
11 | cwd: __dirname
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/test/test-2.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('2.js\n')
9 |
10 | await waitForOutput('Hello p2p world!', 'node', [path.join(__dirname, '../2.js')], {
11 | cwd: __dirname
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/test/test-3.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('3.js\n')
9 |
10 | await waitForOutput('node 3 failed to dial to node 1 with:', 'node', [path.join(__dirname, '../3.js')], {
11 | cwd: __dirname
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/test/test-4.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { fileURLToPath } from 'url'
3 | import { waitForOutput } from 'test-ipfs-example/node'
4 |
5 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
6 |
7 | export async function test () {
8 | process.stdout.write('4.js\n')
9 |
10 | await waitForOutput('node 2 dialed to node 1 successfully', 'node', [path.join(__dirname, '../4.js')], {
11 | cwd: path.join(__dirname, '../')
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/test/test.js:
--------------------------------------------------------------------------------
1 | import { test as test1 } from './test-1.js'
2 | import { test as test2 } from './test-2.js'
3 | import { test as test3 } from './test-3.js'
4 | import { test as test4 } from './test-4.js'
5 |
6 | await test1()
7 | await test2()
8 | await test3()
9 | await test4()
10 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/test_certs/cert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIFlzCCA3+gAwIBAgIUMYedwb9L/BtvZ7Lhu71iSKrXsa4wDQYJKoZIhvcNAQEL
3 | BQAwajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlZBMREwDwYDVQQHDAhTb21lQ2l0
4 | eTESMBAGA1UECgwJTXlDb21wYW55MRMwEQYDVQQLDApNeURpdmlzaW9uMRIwEAYD
5 | VQQDDAkxMjcuMC4wLjEwHhcNMjEwNDI4MDIzMjA5WhcNMjIwNDI4MDIzMjA5WjBq
6 | MQswCQYDVQQGEwJVUzELMAkGA1UECAwCVkExETAPBgNVBAcMCFNvbWVDaXR5MRIw
7 | EAYDVQQKDAlNeUNvbXBhbnkxEzARBgNVBAsMCk15RGl2aXNpb24xEjAQBgNVBAMM
8 | CTEyNy4wLjAuMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANNhXBu0
9 | GH1Kzl9iaQxCxEnyyAShS5FYScdKxqpYsgJT4poLWLQBZQEFLEqbdillIlTZqMss
10 | jWqkFL2xmjqdcnOKFEZUarntVE2hxFYYQex2Fi8MYwFj+Pvt74d02xPyfzFNFgyX
11 | a1EakoGBwClaf3I7jW7raPudjcf4HnwQ7r/NwiO8FqHFZgLcTnwI8bk+cxDoDAqu
12 | mhqMB5nnerqvKEyR9Fb2PoL+8PwOPJOOKTDVwLMeMJu2WLR8AU2FzOj5SVI2qsu9
13 | Ps5azysD8KQAMcw4y9s6do36SaMQS85fbvXBV7XBqMD34HPBUbFiCoFoaCzK9Zfb
14 | pCXyVJMUNmw5hyq9nbjUt4Kvr/58bU2gjUKSdPf6KhBxFnDZwl+2qqPdVIb/qtwz
15 | HExtJWq3upklXNOg3HoR6vcr1O9ReJHrzLRMEb51WP1aN/qJ2/lRskcZ4A806qwr
16 | W67BvnOg6s3ZtxHN9v3bsyfsvC66w8PEfCnCVxugC7cUW0gtW54AU75T3ukg7X+m
17 | vECr/+qIzNEBIxxCPgefCG/JAdJhQ5SCvoARAVPStUIWDmigDeOt7go5nKbdVIJ4
18 | 7bbBFUhHT2mTHu30fHhRqSDcHzwE7Zz6YJIJmKq29UmzUazFnKlLU67MjLJwiDPm
19 | fC3GyOdAWkkZE5hjtkiy+3yWoEHhaJYRI1u3AgMBAAGjNTAzMAsGA1UdDwQEAwIE
20 | MDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHREECDAGhwR/AAABMA0GCSqGSIb3
21 | DQEBCwUAA4ICAQCx/ynu4iCQAK8VId/QQe7GqgOpFgx+6Mce9GQC6ZVEjAPgapsS
22 | Pl+l6+11cFjHKv0+Z/iN2JgkFmNXfwJcfYI0tHbMK+0U9hgKb1eFgiIwCqb4cPOz
23 | wMwusZ95BjIbtcEbL/+pMUpNhmjPz1fOILJZtDVq++lqJCv7t8+SoAmMVYtlcLNg
24 | muuV/UYR3uqvnAJmjgJVWs4otDGrxCYJE48M+9L2Gm05Htpi9WL1bZaQ+fJ85m85
25 | daedLc6R1/ZRTIH6i73sD4rYs0bx1fCJvkbcgXtKMHEkiHuG/MzR7Pa4cJAVKCx9
26 | lRTgrO7Gkllt2+jp4qg0YhdNq89e0DNA5cyB9H4udRgHQOcrlVRiX9OD/Kz+F5m/
27 | fQwMdbnqdg3ar5DSa8Q5g3bdLbNSCcI9sjCLTkNxUC/XTWGdG03RCVIt1qvBvZHk
28 | JaG6xGpbRZ5CN0T9eindd38JBrkPAPfgl6qhwvcqh6uVFYua+7KmF9K+mKarlmMw
29 | 6RWaw2j4sMgUyRIS6fR9vDc20SrtoNvKQM1U6+0VYs1nizfkmsqqqRODmERKbKwc
30 | ahKJFubXfr8gz+PipAKFZbxr2EPAyoiNkx+0eM6Eedo55oP2BoGHEfXEoAonyMFM
31 | F/xTbpFtdRYE2hwsZCk86fpbcPTmdCY8txeZ7+4Bme2d9XXsTAxF64usqQ==
32 | -----END CERTIFICATE-----
33 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-transports/test_certs/key.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDTYVwbtBh9Ss5f
3 | YmkMQsRJ8sgEoUuRWEnHSsaqWLICU+KaC1i0AWUBBSxKm3YpZSJU2ajLLI1qpBS9
4 | sZo6nXJzihRGVGq57VRNocRWGEHsdhYvDGMBY/j77e+HdNsT8n8xTRYMl2tRGpKB
5 | gcApWn9yO41u62j7nY3H+B58EO6/zcIjvBahxWYC3E58CPG5PnMQ6AwKrpoajAeZ
6 | 53q6ryhMkfRW9j6C/vD8DjyTjikw1cCzHjCbtli0fAFNhczo+UlSNqrLvT7OWs8r
7 | A/CkADHMOMvbOnaN+kmjEEvOX271wVe1wajA9+BzwVGxYgqBaGgsyvWX26Ql8lST
8 | FDZsOYcqvZ241LeCr6/+fG1NoI1CknT3+ioQcRZw2cJftqqj3VSG/6rcMxxMbSVq
9 | t7qZJVzToNx6Eer3K9TvUXiR68y0TBG+dVj9Wjf6idv5UbJHGeAPNOqsK1uuwb5z
10 | oOrN2bcRzfb927Mn7LwuusPDxHwpwlcboAu3FFtILVueAFO+U97pIO1/prxAq//q
11 | iMzRASMcQj4HnwhvyQHSYUOUgr6AEQFT0rVCFg5ooA3jre4KOZym3VSCeO22wRVI
12 | R09pkx7t9Hx4Uakg3B88BO2c+mCSCZiqtvVJs1GsxZypS1OuzIyycIgz5nwtxsjn
13 | QFpJGROYY7ZIsvt8lqBB4WiWESNbtwIDAQABAoICAQCpGV3iG7Trpohp7gQzdsYo
14 | kjxI1+/oGkULVVqQs9vT2N+SdDlF50eyBT1lgfCJNQq97lIGF2IaSaD+D7Jd6c7B
15 | d1i42pd2ndGvORYj+cvjKqSchsA9QIjSoYnZRzZrQrdV7WESOZ/0hdlmGTJs4qTJ
16 | 8bI3ZcPaZjQiIO/iOHmGn0gL5lAEojH1X+C5gT4+/yJ2B+x6LyvAyPzbtj6MUctf
17 | VfOuDdf8W47VVV5IfJWfJ6C8qg4gw0M7P2ibZ8qBJcvuJSWFT6OK2UKaGtDLogw0
18 | X8tVWfO1qOB3vnWmZtoRZ9aO5JnnpWS9tY1w5gmZdLjB/Kt0DJXIdZALCURwV6U0
19 | q5XR0SETEgdRrNX92PA2lmxO9fAgXRSjP/OoeDjAVhnRfYyShDbEIb8GHk7nE+is
20 | 6ak5ufxKE53S8wB9L7MTPqTvxusBHi8saLevdnPBMQPvtEVkg2Iw/iPBsegUuUjD
21 | uzXlq4WUMCUBJEMVPuYEsaQizxpp2oM6AZj/ecuTKFX5CirFFWKOQ4cp+O8lrfI5
22 | ruwHrMkfjowDYcQaOLHq13anvt8+8LBlngVw+jiAGB/bGwrAwEZWUc8i1HbH/G8e
23 | sm0kMuCqV1GbRyMCUO3pWjzrsz8LEy74Jr0z7KZn52vLWrTkiD4NRXahxTBhHpXb
24 | AVclJ+a4BKk2rRJVRFRRQQKCAQEA7+uTl2ZHp1v7A8/I2zPIxoVz0fiwxwAjuv34
25 | cV+uxG0n5Tko4PKMxavddRFKNeGvrz0aO/GNX8NIW7pDqZ2CwHyskgUX/bFAqGKF
26 | Z/z2DmiZ2rdSUH89O3ysq+OF3RjX/FBNJ0SVdwtrpz3kCSWpa4PnmN7+IevL6zxY
27 | 8gLrs07Ge+ci94FZaDHBNrkGQ00krbOmwIvnc90hyRPCKfMS+u2/ejKZ5QDyRG+H
28 | jbQ008ZV2OqUdS6h1twfoJ1Q4QhHijB6PegRLGdZGuUXIQfFP8dIUsQluKSUFyOy
29 | bL9W2yBwtbn3EwYDHLJQnLICxfcTBWg/2vOIucsSjxG7KNY0yQKCAQEA4YwcVpi3
30 | D+8OcnbpRBRlHo84DRZorp0RO8vhxevvB1CcBnkLRIYXlS2JIfrnhZAI/5jBk1ei
31 | FmgRFyAjZ8gDdkDCiDMQMDUwUhLGSVurI9sk16B4TQKCM+iE0LDrXIy9ezJRJkj0
32 | rOt8sqo2/TOttm2KEXY8Cco59tU4bMZg5Tr9l7SMTTj4skTO6Jn6/6hX3XuFkJw7
33 | B0DsSzIqXyRHAzOidagIEoIr7k4cEGXsrSWoSiHg/eky1ihCyUw3vDDOmoViBR7s
34 | h5nLjQNNAzOtyoKLqST7B7uXkdUo5nV2IUHSGD5LNxlTaNp0XL9Ph3EBtcuwNuB6
35 | zyKXc+O5iNfMfwKCAQEA5/RJKCnRgsORxpif5xWEujIRzOHz/yFqagHarbnFHNEv
36 | rhT6Kak2YnIL1H/X0IoWsYSQlX2uofQKQ+ysOBM5c2HV8gKMtFAnY+SEeAn/1eRZ
37 | QzTTl1G84INj6Xc6V40KXD1CqoFLQ+G9vd4/Vnyb9H99bLXC2wa+ivo4QBqEyEGT
38 | 8fyAOOxMhUj9NSvjGzQ9DtbOk/9u0PztChtZL/d61TEAW2MKmHW2xGVTl7OvE0QA
39 | gYwh5b0k6La+uSj/JeE8USUXOjzgRZ7RbggouV1q3YOMr8BFe+NZ7Zksiqjej1Io
40 | xfk6H6FDZv4ao7QSrFR4hlTIz6V9/aqQkdOhsBSQyQKCAQEAzHwz4Qr5xVduGLbY
41 | S6HV/7vHDI6Jf+3lBvqUidWa013w5yls3sZXsSckkgshRoVMszayIbystnXJMNcx
42 | YlEDWn3iIItzHNHMKkzdOvsCETMIlvnkt6UTmK4xY+dSq4jp7Ty0N+qi8fdaCb2q
43 | tyrYTnHHYId6bUHMBY5QZsYAaTNvYNAO96A0UaNyl42q84iTiLkJYg9SsQPad15W
44 | 7gU84Jk6rEMYdndQDvEAHpnZ1y0yA2vtySZYsbK0wj34tgTl+0/8izn7JgF4ezNH
45 | 6iQ7Z0OuDT763IrmIxBH0ZEi9YnwSYyIsr6iUYjlQIUuPFRnQYQXEdm5Xfw1pZsL
46 | xhYoTwKCAQB9edDe4LX+0z9i4qr0iHV8H/WoyI5UD/Pc217PKkYM3+ewR9SL9D9z
47 | TS78Sl7HgRgEmIu+MR/u5B2ePf7jkvB/oxyPwqAzJeJ72mV3Mevm27G/Ndd8lt5W
48 | FBCGOx7ZeP4/Cv4mvPD979ix2IalDoWMSWJnpQPN+B1jGeCrUYAXQc1k/vU99gLa
49 | 8Tuu3WfBpVAsO7hAC9mu6tuLyfKVqiMOVs2aky9xLqiqW/6uIcGu+owrr+gkDDY/
50 | JfBSUfxYKcjtJiHOEbFGrrRe93XsngmaTz/Hv9A/QLVCuJgWEHlt4WHSc+BtAtaV
51 | 9avp6VlyVNfe4KEKW7IekrI0cmfMdXkl
52 | -----END PRIVATE KEY-----
53 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-webrtc-private-to-private/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # ⚠️ IMPORTANT ⚠️
2 |
3 | # Please do not create a Pull Request for this repository
4 |
5 | The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
6 |
7 | Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
8 |
9 | ## Contributing
10 |
11 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
12 |
13 | 1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
14 | 2. Create your Feature Branch (`git checkout -b feature/amazing-example`)
15 | 3. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
16 | 4. Push to the Branch (`git push origin feature/amazing-example`)
17 | 5. Open a Pull Request
18 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-webrtc-private-to-private/.github/workflows/sync.yml:
--------------------------------------------------------------------------------
1 | name: pull
2 |
3 | on:
4 | workflow_dispatch
5 |
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 | - name: Pull from another repository
12 | uses: ipfs-examples/actions-pull-directory-from-repo@main
13 | with:
14 | source-repo: libp2p/js-libp2p-examples
15 | source-folder-path: examples/${{ github.event.repository.name }}
16 | source-branch: main
17 | target-branch: main
18 | git-username: github-actions
19 | git-email: github-actions@github.com
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-webrtc-private-to-private/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-webrtc-private-to-private/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-webrtc-private-to-private/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-webrtc-private-to-private/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | js-libp2p WebRTC
7 |
24 |
25 |
26 |
27 |
28 | Remote MultiAddress:
29 |
30 | Connect
31 |
32 |
33 | Message:
34 |
35 | Send
36 |
37 |
38 |
Active Connections:
39 |
40 |
41 |
42 |
Listening addresses:
43 |
44 |
45 |
Output:
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-webrtc-private-to-private/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@libp2p/example-webrtc-private-to-private",
3 | "version": "1.0.0",
4 | "description": "Connect a browser to another browser",
5 | "type": "module",
6 | "scripts": {
7 | "start": "vite",
8 | "build": "vite build",
9 | "relay": "node relay.js",
10 | "test:firefox": "npm run build && playwright test --browser=firefox test",
11 | "test:chrome": "npm run build && playwright test test",
12 | "test": "npm run build && test-browser-example test"
13 | },
14 | "dependencies": {
15 | "@chainsafe/libp2p-noise": "^16.0.0",
16 | "@chainsafe/libp2p-yamux": "^7.0.0",
17 | "@libp2p/circuit-relay-v2": "^3.0.0",
18 | "@libp2p/identify": "^3.0.1",
19 | "@libp2p/ping": "^2.0.1",
20 | "@libp2p/webrtc": "^5.0.0",
21 | "@libp2p/websockets": "^9.0.0",
22 | "@multiformats/multiaddr": "^12.0.0",
23 | "it-pushable": "^3.2.0",
24 | "libp2p": "^2.0.0",
25 | "vite": "^6.0.3"
26 | },
27 | "devDependencies": {
28 | "test-ipfs-example": "^1.0.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-webrtc-private-to-private/relay.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { noise } from '@chainsafe/libp2p-noise'
4 | import { yamux } from '@chainsafe/libp2p-yamux'
5 | import { circuitRelayServer } from '@libp2p/circuit-relay-v2'
6 | import { identify } from '@libp2p/identify'
7 | import { webSockets } from '@libp2p/websockets'
8 | import * as filters from '@libp2p/websockets/filters'
9 | import { createLibp2p } from 'libp2p'
10 |
11 | const server = await createLibp2p({
12 | addresses: {
13 | listen: ['/ip4/127.0.0.1/tcp/0/ws']
14 | },
15 | transports: [
16 | webSockets({
17 | filter: filters.all
18 | })
19 | ],
20 | connectionEncrypters: [noise()],
21 | streamMuxers: [yamux()],
22 | services: {
23 | identify: identify(),
24 | relay: circuitRelayServer({
25 | // disable max reservations limit for demo purposes. in production you
26 | // should leave this set to the default of 15 to prevent abuse of your
27 | // node by network peers
28 | reservations: {
29 | maxReservations: Infinity
30 | }
31 | })
32 | }
33 | })
34 |
35 | console.info('The relay node is running and listening on the following multiaddrs:')
36 | console.info('')
37 | console.info(server.getMultiaddrs().map((ma) => ma.toString()).join('\n'))
38 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-webrtc-private-to-private/test/index.spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import { noise } from '@chainsafe/libp2p-noise'
3 | import { yamux } from '@chainsafe/libp2p-yamux'
4 | import { circuitRelayServer } from '@libp2p/circuit-relay-v2'
5 | import { identify } from '@libp2p/identify'
6 | import { webSockets } from '@libp2p/websockets'
7 | import * as filters from '@libp2p/websockets/filters'
8 | import { createLibp2p } from 'libp2p'
9 | import { setup, expect } from 'test-ipfs-example/browser'
10 |
11 | // Setup
12 | const test = setup()
13 |
14 | // DOM
15 | const connectBtn = '#connect'
16 | const connectAddr = '#peer'
17 | const messageInput = '#message'
18 | const sendBtn = '#send'
19 | const output = '#output'
20 | const listeningAddresses = '#multiaddrs'
21 |
22 | let url
23 |
24 | // we spawn a js libp2p relay
25 | async function spawnRelay () {
26 | const relayNode = await createLibp2p({
27 | addresses: {
28 | listen: ['/ip4/127.0.0.1/tcp/0/ws']
29 | },
30 | transports: [
31 | webSockets({
32 | filter: filters.all
33 | })
34 | ],
35 | connectionEncrypters: [noise()],
36 | streamMuxers: [yamux()],
37 | services: {
38 | identify: identify(),
39 | relay: circuitRelayServer()
40 | }
41 | })
42 |
43 | const relayNodeAddr = relayNode.getMultiaddrs()[0].toString()
44 |
45 | return { relayNode, relayNodeAddr }
46 | }
47 |
48 | test.describe('browser to browser example:', () => {
49 | let relayNode
50 | let relayNodeAddr
51 |
52 | // eslint-disable-next-line no-empty-pattern
53 | test.beforeAll(async ({ servers }, testInfo) => {
54 | testInfo.setTimeout(5 * 60_000)
55 | const r = await spawnRelay()
56 | relayNode = r.relayNode
57 | relayNodeAddr = r.relayNodeAddr
58 | url = servers[0].url
59 | }, {})
60 |
61 | test.afterAll(() => {
62 | relayNode.stop()
63 | })
64 |
65 | test.beforeEach(async ({ page }) => {
66 | await page.goto(url)
67 | })
68 |
69 | test('should connect to another browser peer and send a message', async ({ page: pageA, context }) => {
70 | // load second page
71 | const pageB = await context.newPage()
72 | await pageB.goto(url)
73 |
74 | // connect the first page to the relay
75 | const relayedAddressA = await dialRelay(pageA, relayNodeAddr)
76 |
77 | // dial first page from second page over relay
78 | await dialPeerOverRelay(pageB, relayedAddressA)
79 |
80 | // stop the relay
81 | await relayNode.stop()
82 |
83 | // send a message from a to b
84 | await sendMessage(pageA, pageB, 'hello B from A')
85 |
86 | // send a message from b to a
87 | await sendMessage(pageB, pageA, 'hello A from B')
88 | })
89 | })
90 |
91 | async function sendMessage (senderPage, recipientPage, message) {
92 | // send the message to the peer over webRTC
93 | await senderPage.fill(messageInput, message)
94 | await senderPage.click(sendBtn)
95 |
96 | // check the message was sent
97 | await expect(senderPage.locator(output)).toContainText(`Sending message '${message}'`)
98 | // check the message was received
99 | await expect(recipientPage.locator(output)).toContainText(`Received message '${message}'`)
100 | }
101 |
102 | async function dialRelay (page, address) {
103 | // add the go libp2p multiaddress to the input field and submit
104 | await page.fill(connectAddr, address)
105 | await page.click(connectBtn)
106 |
107 | const outputLocator = page.locator(output)
108 | await expect(outputLocator).toContainText(`Dialing '${address}'`)
109 | await expect(outputLocator).toContainText('Connected to relay')
110 |
111 | const multiaddrsLocator = page.locator(listeningAddresses)
112 | await expect(multiaddrsLocator).toHaveText(/webrtc/)
113 |
114 | const multiaddrs = await page.textContent(listeningAddresses)
115 | const addr = multiaddrs.split(address).filter(str => str.includes('webrtc')).pop()
116 |
117 | return address + addr
118 | }
119 |
120 | async function dialPeerOverRelay (page, address) {
121 | // add the go libp2p multiaddr to the input field and submit
122 | await page.fill(connectAddr, address)
123 | await page.click(connectBtn)
124 |
125 | const outputLocator = page.locator(output)
126 | await expect(outputLocator).toContainText(`Dialing '${address}'`)
127 | await expect(outputLocator).toContainText(`Connected to '${address}'`)
128 | }
129 |
--------------------------------------------------------------------------------
/examples/js-libp2p-example-webrtc-private-to-private/vite.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | build: {
3 | target: 'es2022'
4 | },
5 | optimizeDeps: {
6 | esbuildOptions: { target: 'es2022', supported: { bigint: true } }
7 | },
8 | server: {
9 | open: true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "js-libp2p-examples",
3 | "version": "1.0.0",
4 | "description": "Examples of how to use js-libp2p",
5 | "type": "module",
6 | "scripts": {
7 | "reset": "aegir run clean && aegir clean **/node_modules **/package-lock.json",
8 | "test": "aegir run --concurrency 1 test",
9 | "clean": "aegir run clean",
10 | "build": "aegir run build",
11 | "lint": "aegir exec aegir -- lint --files '**/*.{js,ts,jsx}' '!**/node_modules/**' '!**/dist/**'",
12 | "lint:fix": "aegir exec aegir -- lint --files '**/*.{js,ts,jsx}' '!**/node_modules/**' '!**/dist/**' --fix",
13 | "dep-check": "aegir run dep-check"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/libp2p/js-libp2p-examples.git"
18 | },
19 | "author": "",
20 | "license": "ISC",
21 | "bugs": {
22 | "url": "https://github.com/libp2p/js-libp2p-examples/issues"
23 | },
24 | "homepage": "https://github.com/libp2p/js-libp2p-examples#readme",
25 | "eslintConfig": {
26 | "extends": "ipfs",
27 | "parserOptions": {
28 | "project": true,
29 | "sourceType": "module"
30 | }
31 | },
32 | "devDependencies": {
33 | "aegir": "^45.0.8"
34 | },
35 | "workspaces": [
36 | "examples/*"
37 | ],
38 | "private": true
39 | }
40 |
--------------------------------------------------------------------------------