├── .aegir.js ├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .mocharc.json ├── .prettierignore ├── .prettierrc ├── .release-please-manifest.json ├── .release-please.json ├── CHANGELOG.md ├── CODEOWNERS ├── LICENSE ├── LICENSE-MIT ├── README.md ├── chai-global.js ├── docs ├── .mocharc.json ├── .nojekyll ├── CNAME ├── README.md ├── _navbar.md ├── _sidebar.md ├── coverpage.md ├── examples.md ├── examples │ ├── document-store.spec.ts │ ├── document-store.ts │ ├── text-store.spec.ts │ └── text-store.ts ├── getting-started.md ├── index.html ├── media │ └── favicon.ico ├── modules │ ├── client │ │ ├── README.md │ │ ├── bootstrap.spec.ts │ │ ├── bootstrap.ts │ │ ├── connectivity-direct.spec.ts │ │ ├── connectivity-direct.ts │ │ ├── connectivity-relay.spec.ts │ │ ├── connectivity-relay.ts │ │ └── example.ts │ ├── deploy │ │ ├── README.md │ │ ├── manage │ │ │ └── README.md │ │ ├── publish │ │ │ ├── README.md │ │ │ ├── p1.svg │ │ │ ├── p2.svg │ │ │ ├── p3.svg │ │ │ ├── p4.svg │ │ │ └── p5.svg │ │ └── server │ │ │ ├── README.md │ │ │ ├── automatic.md │ │ │ └── custom.md │ ├── encoding │ │ ├── README.md │ │ ├── borsh.ts │ │ ├── index.spec.ts │ │ └── json.ts │ ├── encryption │ │ ├── README.md │ │ ├── encrypted-document.spec.ts │ │ ├── encrypted-document.ts │ │ ├── encrypted-log.spec.ts │ │ └── encrypted-log.ts │ └── program │ │ ├── README.md │ │ ├── composition │ │ ├── README.md │ │ ├── composition.spec.ts │ │ └── composition.ts │ │ ├── document-store │ │ ├── README.md │ │ ├── document-store.spec.ts │ │ ├── document-store.ts │ │ ├── migration-centralized.ts │ │ ├── migration-owned.ts │ │ ├── migration-types.ts │ │ ├── multisig.spec.ts │ │ ├── multisig.ts │ │ ├── replication-degree.spec.ts │ │ ├── replication-degree.ts │ │ ├── roles.spec.ts │ │ └── roles.ts │ │ ├── example.ts │ │ └── rpc │ │ ├── README.md │ │ ├── rpc.spec.ts │ │ ├── rpc.ts │ │ ├── rpc1.png │ │ └── rpc2.png ├── package.json ├── peerbit-logo.png ├── styles.css ├── topics │ ├── custom-domain │ │ ├── README.md │ │ └── buffer.mp4 │ ├── difference │ │ └── difference.md │ ├── forward-secrecy │ │ └── README.md │ ├── integrity │ │ └── integrity.md │ ├── sharding │ │ ├── addressing.md │ │ ├── ca0.png │ │ ├── ca0b.png │ │ ├── ca1.png │ │ ├── ca2.png │ │ ├── ca3.png │ │ ├── cpu-toggle.mp4 │ │ ├── p1.png │ │ ├── p10.png │ │ ├── p11.png │ │ ├── p12.png │ │ ├── p13.png │ │ ├── p14.png │ │ ├── p15.png │ │ ├── p16.png │ │ ├── p17.png │ │ ├── p18.png │ │ ├── p2.png │ │ ├── p4.png │ │ ├── p5.png │ │ ├── p6.png │ │ ├── p7.png │ │ ├── p8.png │ │ ├── p9.png │ │ ├── sharding.md │ │ └── storage-toggle.mp4 │ ├── sqlite-integration │ │ └── README.md │ ├── wallet-integration │ │ ├── README.md │ │ ├── ethersproject.spec.ts │ │ └── ethersproject.ts │ └── zero-knowledge │ │ └── README.md ├── tsconfig.json └── videostream.gif ├── package.json ├── packages ├── clients │ ├── peerbit-proxy │ │ ├── proxy │ │ │ ├── .gitignore │ │ │ ├── CHANGELOG.md │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── blocks.ts │ │ │ │ ├── client.ts │ │ │ │ ├── connection.ts │ │ │ │ ├── host.ts │ │ │ │ ├── index.ts │ │ │ │ ├── indexer.ts │ │ │ │ ├── keychain.ts │ │ │ │ ├── lifecycle.ts │ │ │ │ ├── message.ts │ │ │ │ ├── native.ts │ │ │ │ ├── network.ts │ │ │ │ ├── pubsub.ts │ │ │ │ └── storage.ts │ │ │ ├── test │ │ │ │ ├── connection.spec.ts │ │ │ │ ├── host-client.spec.ts │ │ │ │ └── utils.ts │ │ │ └── tsconfig.json │ │ └── window │ │ │ ├── .gitignore │ │ │ ├── CHANGELOG.md │ │ │ ├── README.md │ │ │ ├── e2e │ │ │ └── browser │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── child │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── index.html │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ │ ├── manifest.json │ │ │ │ │ └── robots.txt │ │ │ │ ├── src │ │ │ │ │ ├── App.tsx │ │ │ │ │ ├── db.ts │ │ │ │ │ ├── index.css │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── vite-env.d.ts │ │ │ │ ├── tsconfig.json │ │ │ │ ├── tsconfig.node.json │ │ │ │ └── vite.config.ts │ │ │ │ ├── package.json │ │ │ │ ├── parent │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── index.html │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ │ ├── manifest.json │ │ │ │ │ └── robots.txt │ │ │ │ ├── src │ │ │ │ │ ├── App.tsx │ │ │ │ │ ├── index.css │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── vite-env.d.ts │ │ │ │ ├── tsconfig.json │ │ │ │ ├── tsconfig.node.json │ │ │ │ └── vite.config.ts │ │ │ │ ├── playwright.config.ts │ │ │ │ ├── plugin.js │ │ │ │ └── tests │ │ │ │ └── iframe.browser.spec.ts │ │ │ ├── package.json │ │ │ ├── src │ │ │ └── index.ts │ │ │ └── tsconfig.json │ ├── peerbit-server │ │ ├── README.md │ │ ├── frontend │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ ├── android-chrome-192x192.png │ │ │ │ ├── android-chrome-512x512.png │ │ │ │ ├── favicon-16x16.png │ │ │ │ ├── favicon-32x32.png │ │ │ │ ├── favicon.ico │ │ │ │ ├── manifest.json │ │ │ │ └── robots.txt │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── vite-env.d.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ ├── node │ │ │ ├── .gitignore │ │ │ ├── .prettierignore │ │ │ ├── CHANGELOG.md │ │ │ ├── LICENSE │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── aws.browser.ts │ │ │ │ ├── aws.ts │ │ │ │ ├── bin.ts │ │ │ │ ├── cli.ts │ │ │ │ ├── client.ts │ │ │ │ ├── config.browser.ts │ │ │ │ ├── config.ts │ │ │ │ ├── docker.browser.ts │ │ │ │ ├── docker.ts │ │ │ │ ├── domain.ts │ │ │ │ ├── index.ts │ │ │ │ ├── nginx-template.conf │ │ │ │ ├── peerbit.ts │ │ │ │ ├── remotes.browser.ts │ │ │ │ ├── remotes.ts │ │ │ │ ├── routes.ts │ │ │ │ ├── server.browser.ts │ │ │ │ ├── server.ts │ │ │ │ ├── session.ts │ │ │ │ ├── signed-request.ts │ │ │ │ ├── trust.browser.ts │ │ │ │ ├── trust.ts │ │ │ │ └── types.ts │ │ │ ├── test │ │ │ │ ├── api.spec.ts │ │ │ │ ├── cli.spec.ts │ │ │ │ ├── client.spec.ts │ │ │ │ ├── config.spec.ts │ │ │ │ ├── domain.integration.spec.ts │ │ │ │ ├── launch.spec.ts │ │ │ │ ├── signed-request.spec.ts │ │ │ │ ├── test.tgz │ │ │ │ └── utils.ts │ │ │ └── tsconfig.json │ │ └── test-lib │ │ │ ├── .gitignore │ │ │ ├── .prettierignore │ │ │ ├── LICENSE │ │ │ ├── package.json │ │ │ ├── src │ │ │ └── index.ts │ │ │ ├── test │ │ │ └── cli.spec.ts │ │ │ └── tsconfig.json │ ├── peerbit │ │ ├── .aegir.js │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── benchmark │ │ │ └── start-stop.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── bootstrap.ts │ │ │ ├── index.ts │ │ │ ├── libp2p.ts │ │ │ ├── peer.ts │ │ │ ├── transports.browser.ts │ │ │ └── transports.ts │ │ ├── test │ │ │ ├── bootstrap.spec.ts │ │ │ ├── connect.spec.ts │ │ │ ├── create.ts │ │ │ ├── identity.spec.ts │ │ │ ├── indexer.spec.ts │ │ │ ├── libp2p.spec.ts │ │ │ ├── node.js │ │ │ ├── shared-program.spec.ts │ │ │ ├── start-stop.spec.ts │ │ │ ├── subprogram.spec.ts │ │ │ └── utils │ │ │ │ └── event-store.ts │ │ └── tsconfig.json │ ├── test-utils │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── log-utils.ts │ │ │ └── session.ts │ │ ├── test │ │ │ └── index.spec.ts │ │ └── tsconfig.json │ └── vite │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── e2e │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── package.json │ │ ├── public │ │ │ ├── manifest.json │ │ │ └── robots.txt │ │ ├── src │ │ │ ├── App.tsx │ │ │ ├── db.ts │ │ │ ├── index.css │ │ │ ├── index.tsx │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ │ ├── package.json │ │ ├── src │ │ └── index.ts │ │ └── tsconfig.json ├── log │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── benchmark │ │ ├── append.ts │ │ ├── memory │ │ │ ├── index.ts │ │ │ ├── insert.ts │ │ │ └── utils.ts │ │ └── payload.ts │ ├── package.json │ ├── src │ │ ├── change.ts │ │ ├── clock.ts │ │ ├── difference.ts │ │ ├── encoding.ts │ │ ├── entry-create.ts │ │ ├── entry-index.ts │ │ ├── entry-shallow.ts │ │ ├── entry-type.ts │ │ ├── entry-v0.ts │ │ ├── entry-with-refs.ts │ │ ├── entry.ts │ │ ├── find-uniques.ts │ │ ├── heads-cache.ts │ │ ├── index.ts │ │ ├── log-errors.ts │ │ ├── log-sorting.ts │ │ ├── log.ts │ │ ├── logger.ts │ │ ├── payload.ts │ │ ├── snapshot.ts │ │ ├── trim.ts │ │ └── utils.ts │ ├── test │ │ ├── append.spec.ts │ │ ├── clock.spec.ts │ │ ├── crdt.spec.ts │ │ ├── delete.spec.ts │ │ ├── drop.spec.ts │ │ ├── encryption.spec.ts │ │ ├── entry.spec.ts │ │ ├── fixtures │ │ │ └── privateKey.ts │ │ ├── from.spec.ts │ │ ├── get-pow-2-refs.spec.ts │ │ ├── heads-tails.spec.ts │ │ ├── join-concurrent.spec.ts │ │ ├── join.spec.ts │ │ ├── load.spec.ts │ │ ├── log.spec.ts │ │ ├── nexts.spec.ts │ │ ├── recover.spec.ts │ │ ├── replicate.spec.ts │ │ ├── signed-log.spec.ts │ │ ├── sorting.spec.ts │ │ ├── trim.spec.ts │ │ └── utils │ │ │ ├── encoding.ts │ │ │ └── log-creator.ts │ └── tsconfig.json ├── programs │ ├── acl │ │ ├── identity-access-controller │ │ │ ├── .gitignore │ │ │ ├── CHANGELOG.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── access.ts │ │ │ │ ├── acl-db.ts │ │ │ │ ├── condition.ts │ │ │ │ └── index.ts │ │ │ ├── test │ │ │ │ └── index.spec.ts │ │ │ └── tsconfig.json │ │ └── trusted-network │ │ │ ├── .gitignore │ │ │ ├── CHANGELOG.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ ├── controller.ts │ │ │ ├── identity-graph.ts │ │ │ └── index.ts │ │ │ ├── test │ │ │ └── index.spec.ts │ │ │ └── tsconfig.json │ ├── clock-service │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── controller.ts │ │ │ └── index.ts │ │ ├── test │ │ │ └── index.spec.ts │ │ └── tsconfig.json │ ├── data │ │ ├── document │ │ │ ├── document │ │ │ │ ├── .gitignore │ │ │ │ ├── CHANGELOG.md │ │ │ │ ├── README.md │ │ │ │ ├── benchmark │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── iterate-replicate-2.ts │ │ │ │ │ ├── iterate-replicate.ts │ │ │ │ │ ├── memory │ │ │ │ │ │ ├── child.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ └── replication.ts │ │ │ │ ├── package.json │ │ │ │ ├── src │ │ │ │ │ ├── borsh.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── domain.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── most-common-query-predictor.ts │ │ │ │ │ ├── operation.ts │ │ │ │ │ ├── prefetch.ts │ │ │ │ │ ├── program.ts │ │ │ │ │ ├── resumable-iterator.ts │ │ │ │ │ └── search.ts │ │ │ │ ├── test │ │ │ │ │ ├── borsh.spec.ts │ │ │ │ │ ├── data.ts │ │ │ │ │ ├── domain.spec.ts │ │ │ │ │ ├── index.spec.ts │ │ │ │ │ ├── most-common-query-predictor.spec.ts │ │ │ │ │ ├── profile.spec.ts │ │ │ │ │ ├── types.spec.ts │ │ │ │ │ └── utils.ts │ │ │ │ └── tsconfig.json │ │ │ └── interface │ │ │ │ ├── .gitignore │ │ │ │ ├── CHANGELOG.md │ │ │ │ ├── package.json │ │ │ │ ├── src │ │ │ │ ├── index.ts │ │ │ │ ├── query.ts │ │ │ │ ├── request.ts │ │ │ │ └── store.ts │ │ │ │ └── tsconfig.json │ │ ├── shared-log │ │ │ ├── .gitignore │ │ │ ├── CHANGELOG.md │ │ │ ├── README.md │ │ │ ├── benchmark │ │ │ │ ├── get-samples.ts │ │ │ │ ├── index.ts │ │ │ │ ├── memory │ │ │ │ │ ├── child.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── partial-sync.ts │ │ │ │ ├── replication-prune.ts │ │ │ │ ├── replication.ts │ │ │ │ ├── to-rebalance.ts │ │ │ │ └── utils.ts │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── blocks.ts │ │ │ │ ├── cpu.ts │ │ │ │ ├── debounce.ts │ │ │ │ ├── errors.ts │ │ │ │ ├── exchange-heads.ts │ │ │ │ ├── index.ts │ │ │ │ ├── integers.ts │ │ │ │ ├── message.ts │ │ │ │ ├── pid.ts │ │ │ │ ├── ranges.ts │ │ │ │ ├── replication-domain-hash.ts │ │ │ │ ├── replication-domain-time.ts │ │ │ │ ├── replication-domain.ts │ │ │ │ ├── replication.ts │ │ │ │ ├── role.ts │ │ │ │ ├── sync │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── rateless-iblt.ts │ │ │ │ │ └── simple.ts │ │ │ │ └── utils.ts │ │ │ ├── test │ │ │ │ ├── append.spec.ts │ │ │ │ ├── cpu.spec.ts │ │ │ │ ├── debounce.spec.ts │ │ │ │ ├── domain-time.spec.ts │ │ │ │ ├── encryption.spec.ts │ │ │ │ ├── events.spec.ts │ │ │ │ ├── join.spec.ts │ │ │ │ ├── leader.spec.ts │ │ │ │ ├── lifecycle.spec.ts │ │ │ │ ├── load.spec.ts │ │ │ │ ├── migration.spec.ts │ │ │ │ ├── network.spec.ts │ │ │ │ ├── observer.spec.ts │ │ │ │ ├── pid.spec.ts │ │ │ │ ├── ranges.spec.ts │ │ │ │ ├── rateless-iblt.spec.ts │ │ │ │ ├── replicate.spec.ts │ │ │ │ ├── replication.spec.ts │ │ │ │ ├── sharding.spec.ts │ │ │ │ ├── statistics.spec.ts │ │ │ │ ├── utils.ts │ │ │ │ └── utils │ │ │ │ │ ├── access.ts │ │ │ │ │ └── stores │ │ │ │ │ ├── encoding.ts │ │ │ │ │ ├── event-store.ts │ │ │ │ │ └── index.ts │ │ │ └── tsconfig.json │ │ └── string │ │ │ ├── .gitignore │ │ │ ├── CHANGELOG.md │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── query.ts │ │ │ ├── range.ts │ │ │ ├── string-index.ts │ │ │ └── string-store.ts │ │ │ ├── test │ │ │ ├── index.spec.ts │ │ │ └── range.spec.ts │ │ │ └── tsconfig.json │ ├── program │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── package.json │ │ ├── src │ │ │ ├── address.ts │ │ │ ├── client.ts │ │ │ ├── handler.ts │ │ │ ├── index.ts │ │ │ ├── program.ts │ │ │ └── utils.ts │ │ ├── test │ │ │ ├── events.spec.ts │ │ │ ├── handler.spec.ts │ │ │ ├── index.spec.ts │ │ │ ├── samples.ts │ │ │ └── utils.ts │ │ └── tsconfig.json │ └── rpc │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── documentation │ │ ├── rpc1.png │ │ └── rpc2.png │ │ ├── package.json │ │ ├── src │ │ ├── controller.ts │ │ ├── encoding.ts │ │ ├── index.ts │ │ ├── io.ts │ │ └── utils.ts │ │ ├── test │ │ └── index.spec.ts │ │ └── tsconfig.json ├── transport │ ├── blocks-interface │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── block.ts │ │ │ └── index.ts │ │ └── tsconfig.json │ ├── blocks │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── benchmark │ │ │ ├── e2e.ts │ │ │ └── multiformats.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── any-blockstore.ts │ │ │ ├── index.ts │ │ │ ├── interface.ts │ │ │ ├── libp2p.ts │ │ │ └── remote.ts │ │ ├── test │ │ │ ├── level.spec.ts │ │ │ └── libp2p.spec.ts │ │ └── tsconfig.json │ ├── libp2p-test-utils │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── session.ts │ │ │ └── transports.ts │ │ ├── test │ │ │ └── index.spec.ts │ │ └── tsconfig.json │ ├── pubsub-interface │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ └── messages.ts │ │ └── tsconfig.json │ ├── pubsub │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── benchmark │ │ │ └── index.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── debounced-set.ts │ │ │ └── index.ts │ │ ├── test │ │ │ └── index.spec.ts │ │ └── tsconfig.json │ ├── stream-interface │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ └── messages.ts │ │ └── tsconfig.json │ └── stream │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── benchmark │ │ └── transfer.ts │ │ ├── e2e │ │ └── browser │ │ │ ├── .gitignore │ │ │ ├── browser-node │ │ │ ├── .gitignore │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ ├── manifest.json │ │ │ │ └── robots.txt │ │ │ ├── src │ │ │ │ ├── App.tsx │ │ │ │ ├── index.css │ │ │ │ ├── index.tsx │ │ │ │ └── vite-env.d.ts │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ │ │ ├── package.json │ │ │ ├── playwright.config.js │ │ │ ├── shared │ │ │ ├── bin.ts │ │ │ └── utils.ts │ │ │ ├── tests │ │ │ └── stream.browser.test.ts │ │ │ └── tsconfig.json │ │ ├── package.json │ │ ├── src │ │ ├── index.ts │ │ ├── logger.ts │ │ ├── pushable-lanes.ts │ │ ├── routes.ts │ │ ├── stats.ts │ │ └── wait-for-event.ts │ │ ├── test │ │ ├── it-pushable.spec.ts │ │ ├── routes.spec.ts │ │ ├── stats.spec.ts │ │ └── stream.spec.ts │ │ └── tsconfig.json └── utils │ ├── any-store │ ├── any-store │ │ ├── .aegir.js │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── level.ts │ │ │ ├── memory.ts │ │ │ ├── store.browser.ts │ │ │ ├── store.ts │ │ │ └── worker-import.d.ts │ │ ├── test │ │ │ └── index.spec.ts │ │ └── tsconfig.json │ ├── interface │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ └── messages.ts │ │ └── tsconfig.json │ └── opfs │ │ ├── .aegir.js │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src │ │ ├── create.ts │ │ ├── index.ts │ │ ├── opfs-store.ts │ │ └── worker.ts │ │ └── tsconfig.json │ ├── cache │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── package.json │ ├── src │ │ └── index.ts │ ├── test │ │ └── cache.spec.ts │ └── tsconfig.json │ ├── crypto │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── benchmark │ │ ├── hash.ts │ │ ├── index.ts │ │ └── peer-ids.ts │ ├── package.json │ ├── src │ │ ├── bytes.ts │ │ ├── ed25519-sign.browser.ts │ │ ├── ed25519-sign.ts │ │ ├── ed25519.ts │ │ ├── encryption.ts │ │ ├── errors.ts │ │ ├── from.ts │ │ ├── hash.browser.ts │ │ ├── hash.ts │ │ ├── index.ts │ │ ├── key.ts │ │ ├── prehash.ts │ │ ├── random.browser.ts │ │ ├── random.ts │ │ ├── sepc256k1.ts │ │ ├── signature.ts │ │ ├── signer.ts │ │ ├── utils.ts │ │ └── x25519.ts │ ├── test │ │ ├── encryption.spec.ts │ │ ├── hash.spec.ts │ │ ├── index.spec.ts │ │ └── random.spec.ts │ └── tsconfig.json │ ├── indexer │ ├── cached-index │ │ ├── .gitignore │ │ ├── package.json │ │ ├── src │ │ │ ├── cache.ts │ │ │ └── index.ts │ │ ├── test │ │ │ └── index.spec.ts │ │ └── tsconfig.json │ ├── interface │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── package.json │ │ ├── src │ │ │ ├── errors.ts │ │ │ ├── id.ts │ │ │ ├── index-engine.ts │ │ │ ├── index.ts │ │ │ ├── query.ts │ │ │ └── utils.ts │ │ ├── test │ │ │ └── id.spec.ts │ │ └── tsconfig.json │ ├── simple │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── benchmark │ │ │ └── index.ts │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ ├── test │ │ │ └── index.spec.ts │ │ └── tsconfig.json │ ├── sqlite3 │ │ ├── .aegir.js │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── benchmark │ │ │ └── index.ts │ │ ├── package.json │ │ ├── src │ │ │ ├── engine.ts │ │ │ ├── index.ts │ │ │ ├── query-planner.ts │ │ │ ├── schema.ts │ │ │ ├── sqlite3-messages.worker.ts │ │ │ ├── sqlite3.browser.ts │ │ │ ├── sqlite3.ts │ │ │ ├── sqlite3.wasm.ts │ │ │ ├── sqlite3.worker.ts │ │ │ └── types.ts │ │ ├── test │ │ │ ├── array.spec.ts │ │ │ ├── basic.spec.ts │ │ │ ├── fixtures.ts │ │ │ ├── index.spec.ts │ │ │ ├── inline.spec.ts │ │ │ ├── query-planner.spec.ts │ │ │ ├── schema.spec.ts │ │ │ ├── shape.spec.ts │ │ │ ├── sort.spec.ts │ │ │ ├── statement.spec.ts │ │ │ ├── table.spec.ts │ │ │ ├── u64.spec.ts │ │ │ └── utils.ts │ │ └── tsconfig.json │ └── tests │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ ├── benchmarks.browser.ts │ │ ├── benchmarks.ts │ │ ├── index.ts │ │ └── tests.ts │ │ └── tsconfig.json │ ├── keychain │ ├── .gitignore │ ├── CHANGELOG.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── interface.ts │ ├── test │ │ ├── encryption.spec.ts │ │ └── index.spec.ts │ └── tsconfig.json │ ├── logger │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── benchmark │ │ └── index.ts │ ├── package.json │ ├── src │ │ └── index.ts │ ├── test │ │ └── index.spec.ts │ └── tsconfig.json │ ├── rateless-iblt │ ├── .gitignore │ ├── CHANGELOG.md │ ├── Cargo.lock │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ ├── TODO │ ├── benches │ │ └── riblt_bench.rs │ ├── package.json │ ├── src │ │ ├── encoding.rs │ │ ├── lib.rs │ │ ├── sketch.rs │ │ ├── testing.rs │ │ ├── tests.rs │ │ └── wasm.rs │ ├── src_js │ │ ├── index.js │ │ ├── wasm-init.browser.js │ │ └── wasm-init.js │ └── test │ │ └── index.spec.ts │ └── time │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── package.json │ ├── src │ ├── aggregators.ts │ ├── hrtime.browser.ts │ ├── hrtime.ts │ ├── index.ts │ ├── metrics.ts │ └── wait.ts │ ├── test │ ├── aggregators.spec.ts │ ├── index.spec.ts │ └── metrics.spec.ts │ └── tsconfig.json ├── patches └── cpy+11.1.0.patch ├── tsconfig.json ├── tsconfig.test.json └── yarn.lock /.aegir.js: -------------------------------------------------------------------------------- 1 | // get monorepo root location using esm and .git folder 2 | import findUp from "find-up"; 3 | import path from "path"; 4 | 5 | const root = path.dirname(findUp.sync(".git", { type: "directory" })); 6 | 7 | export default { 8 | // global options 9 | debug: false, 10 | test: { 11 | /* concurrency: 2, */ 12 | files: [], 13 | before: () => { 14 | return { 15 | env: { TS_NODE_PROJECT: path.join(root, "tsconfig.test.json") }, 16 | }; 17 | }, 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: dao-xyz 4 | patreon: # Replace with a single Patreon username 5 | open_collective: peerbit 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /keystore 3 | /keystore-test 4 | orbitdb 5 | /orbit-db 6 | orbit-db-stores 7 | lib 8 | **/dist 9 | /peerbit 10 | .vscode 11 | /keystore/ 12 | keystore-test 13 | **/__tests__/**/tmp 14 | **/test/**/tmp 15 | /tmp 16 | **/tmp/ 17 | nginx_secrets 18 | nginx 19 | coverage 20 | /test-results/ 21 | /playwright-report/ 22 | /playwright/.cache/ 23 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": ["ts-node/register", "chai-extend/chai-global.js"], 3 | "node-option": [ 4 | "experimental-specifier-resolution=node", 5 | "loader=ts-node/esm", 6 | "no-warnings" 7 | ], 8 | "extension": ["ts"], 9 | "parallel": false, 10 | "spec": ["**/*.spec.ts"], 11 | "ignore": ["**/node_modules/**", "**/dist/**"], 12 | "timeout": "140000", 13 | "exit": true 14 | } 15 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/public/peerbit/** 2 | **/target/** 3 | **/pkg/** 4 | **/dist/** 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "tabWidth": 2, 4 | "plugins": [ 5 | "@trivago/prettier-plugin-sort-imports" 6 | ], 7 | "importOrder": [ 8 | "", 9 | "^[./]" 10 | ], 11 | "importOrderParserPlugins": [ 12 | "typescript", 13 | "tsx", 14 | "jsx", 15 | "decorators" 16 | ], 17 | "importOrderSortSpecifiers": true 18 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.0 (2023-06-07) 4 | 5 | 6 | ### Bug Fixes 7 | 8 | * bootstrap sha ([5174b73](https://github.com/dao-xyz/peerbit/commit/5174b73a34ec0f054f2c9a877fb445b96c120524)) 9 | * rev skip labeling ([44b11a8](https://github.com/dao-xyz/peerbit/commit/44b11a875b60d6ace60b4345ee9440ee14d3ae79)) 10 | * test-release ([a22252e](https://github.com/dao-xyz/peerbit/commit/a22252e5fb843d2186f6009722ab92cb977ef695)) 11 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @marcus-pousette 2 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2018 Protocol Labs Inc. 4 | Copyright (c) 2018 Haja Networks Oy 5 | Copyright (c) 2022 dao.xyz 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /chai-global.js: -------------------------------------------------------------------------------- 1 | import { use } from "chai"; 2 | import chaiAsPromised from "chai-as-promised"; 3 | 4 | use(chaiAsPromised); 5 | /* 6 | process.env.TS_NODE_PROJECT = 'tsconfig.test.json'; 7 | console.log(process.env.TS_NODE_PROJECT) */ 8 | -------------------------------------------------------------------------------- /docs/.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": ["ts-node/register", "chai-extend/chai-global.js"], 3 | "node-option": [ 4 | "experimental-specifier-resolution=node", 5 | "loader=ts-node/esm", 6 | "no-warnings" 7 | ], 8 | "extension": ["ts"], 9 | "spec": ["**/*.spec.ts"], 10 | "ignore": ["**/node_modules/**", "dist/**"], 11 | "timeout": "20000", 12 | "exit": true 13 | } 14 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/.nojekyll -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | peerbit.org -------------------------------------------------------------------------------- /docs/_navbar.md: -------------------------------------------------------------------------------- 1 | * [Home](/) 2 | * [Chat on Matrix](https://matrix.to/#/#peerbit:matrix.org) 3 | 4 | -------------------------------------------------------------------------------- /docs/examples.md: -------------------------------------------------------------------------------- 1 | 2 | # Examples 3 | ## Live demos 4 | [Click here](https://github.com/dao-xyz/peerbit-examples) to see live demos 5 | 6 | ## Code examples 7 | 8 | ### Document database 9 | Below is a short example how you can create a database storing documents 10 | 11 | [documents](./examples/document-store.ts ':include') 12 | 13 | 14 | 15 | ### Collaborative text 16 | Below is a short example how you can create a collaborative text document: 17 | 18 | [text](./examples/text-store.ts ':include') 19 | -------------------------------------------------------------------------------- /docs/examples/document-store.spec.ts: -------------------------------------------------------------------------------- 1 | it("document-store", async () => { 2 | await import("./document-store.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/examples/text-store.spec.ts: -------------------------------------------------------------------------------- 1 | it("text-store", async () => { 2 | await import("./text-store.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | 4 | ## New project 5 | A clone-able boilerplate project can be found [here](https://github.com/dao-xyz/peerbit-getting-started). 6 | 7 | ## Existing project 8 | 9 | ### Install 10 | The client 11 | ```sh 12 | npm install peerbit 13 | ``` 14 | 15 | A store for documents 16 | ```sh 17 | npm install @peerbit/document 18 | ``` 19 | 20 | ### Imports 21 | [import](./examples/document-store.ts ':include :type=code :fragment=imports') 22 | 23 | ### Defining a database 24 | [data](./examples/document-store.ts ':include :type=code :fragment=data') 25 | 26 | ### Inserting the first document 27 | [insert](./examples/document-store.ts ':include :type=code :fragment=insert') 28 | 29 | ### Searching for the document from another peer 30 | [another-client](./examples/document-store.ts ':include :type=code :fragment=another-client') 31 | 32 | Read more about the Document store [here](./modules/program/document-store/README.md). 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/media/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/media/favicon.ico -------------------------------------------------------------------------------- /docs/modules/client/bootstrap.spec.ts: -------------------------------------------------------------------------------- 1 | it("bootstrap", async () => { 2 | await import("./bootstrap.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/modules/client/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { Peerbit } from "peerbit"; 2 | 3 | const peer = await Peerbit.create(); 4 | await peer.bootstrap(); 5 | await peer.stop(); 6 | -------------------------------------------------------------------------------- /docs/modules/client/connectivity-direct.spec.ts: -------------------------------------------------------------------------------- 1 | it("connectivity", async () => { 2 | await import("./connectivity-direct.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/modules/client/connectivity-direct.ts: -------------------------------------------------------------------------------- 1 | import type { Multiaddr } from "@multiformats/multiaddr"; 2 | import { expect } from "chai"; 3 | import { Peerbit } from "peerbit"; 4 | 5 | const peerA = await Peerbit.create(); 6 | const peerB = await Peerbit.create(); 7 | 8 | // When testing locally you can do 9 | await peerA.dial(peerB); 10 | 11 | // In "real" scenarios you only have the other peers address 12 | // you can do 13 | const multaddrs: Multiaddr[] = peerB.libp2p.getMultiaddrs(); 14 | 15 | /* [ 16 | '/ip4/127.0.0.1/tcp/62991/ws/p2p/12D3KooWDebLLpnJJQvUo5LEkEURtLUGJwkiH5cAgS1mnSLfup7N', 17 | '/ip4/127.0.0.1/tcp/62992/p2p/12D3KooWDebLLpnJJQvUo5LEkEURtLUGJwkiH5cAgS1mnSLfup7N' 18 | ] */ 19 | console.log(multaddrs.map((x) => x.toString())); 20 | 21 | await peerA.dial(multaddrs); 22 | 23 | // Connected! 24 | 25 | // We can dial an address directly from a string. This one below is malformed and will fail 26 | await expect(peerA.dial("/ip4/123.4.5...")).rejectedWith("invalid ip address"); 27 | 28 | await peerA.stop(); 29 | await peerB.stop(); 30 | -------------------------------------------------------------------------------- /docs/modules/client/connectivity-relay.spec.ts: -------------------------------------------------------------------------------- 1 | it("connectivity", async () => { 2 | // TMP disable until bootstrap nodes have migrated 3 | // await import("./connectivity-relay.js"); 4 | }); 5 | -------------------------------------------------------------------------------- /docs/modules/client/connectivity-relay.ts: -------------------------------------------------------------------------------- 1 | import { Peerbit } from "peerbit"; 2 | 3 | const peerA = await Peerbit.create(); 4 | const peerB = await Peerbit.create(); 5 | 6 | // this address was obtained by deploying a server node using the CLI 7 | 8 | const relayAddress = 9 | "/dns4/dfe9b412f7ba58031a8c2d58509f5fafa8375575.peerchecker.com/tcp/4003/wss/p2p/12D3KooWEawsHtSUQqjXuR7NgrumxL9maokBmuqwFSpCkeF9vcyd"; 10 | 11 | /* 12 | // To test locally can also do 13 | const multaddrs: Multiaddr[] = peer2.libp2p.getMultiaddrs(); 14 | const relay = await Peerbit.create() 15 | relayAddress = relay.libp2p.getMultiaddrs()[0].toString() 16 | */ 17 | 18 | /* 19 | ┌─┐ 20 | │A│ 21 | └△┘ 22 | ┌▽────┐ 23 | │Relay│ 24 | └△────┘ 25 | ┌▽┐ 26 | │B│ 27 | └─┘ 28 | 29 | */ 30 | 31 | await peerA.dial(relayAddress); 32 | await peerB.dial(relayAddress); 33 | 34 | // Connected (in-directly)! 35 | 36 | await peerA.stop(); 37 | await peerB.stop(); 38 | -------------------------------------------------------------------------------- /docs/modules/client/example.ts: -------------------------------------------------------------------------------- 1 | /// [memory] 2 | import { Peerbit } from "peerbit"; 3 | 4 | // Store only in memory 5 | const clientInMemory = await Peerbit.create(); 6 | 7 | // Store content on disc when possible 8 | const clientWithStorage = await Peerbit.create({ 9 | directory: "/path/somewhere", 10 | }); 11 | /// [memory] 12 | 13 | /// [stop] 14 | await clientInMemory.stop(); 15 | /// [stop] 16 | 17 | await clientWithStorage.stop(); 18 | -------------------------------------------------------------------------------- /docs/modules/deploy/README.md: -------------------------------------------------------------------------------- 1 | ## Deployment Options with Peerbit 2 | 3 | ### Serverless Deployment 4 | As Peerbit currently revolves around JavaScript modules, you have the flexibility to deploy your projects using various package managers such as NPM or Github Packages. By doing so, you can effortlessly incorporate them directly into your applications. This approach works seamlessly with projects like React applications or Electron apps. 5 | 6 | ### Server Deployment 7 | In certain scenarios, deploying a Peerbit instance on a server accessible via a domain is beneficial. This choice is driven by a couple of key reasons: 8 | 9 | 1. **Hole Punching**: Direct browser-to-browser connections require an intermediary peer to facilitate communication. This peer assists browser clients in discovering and connecting to others effectively. While there exist a [bootstrapping network](/modules/client/?id=bootstrapping) that you can use for hole punching, some apps might require dedicated nodes to relay data when direct connections are not possible. 10 | 11 | 2. **Persistent Replicator**: While browser clients can store data on their own, there are instances where maintaining an always-online node is crucial. 12 | 13 | For deploying a server node, Peerbit offers a convenient CLI. Further details can be found [here](/modules/deploy/server/). -------------------------------------------------------------------------------- /docs/modules/deploy/server/README.md: -------------------------------------------------------------------------------- 1 | # Setting up a server node 2 | ## Testing locally 3 | 4 | To run a node (and relay) locally you can use the CLI 5 | 6 | ```sh 7 | npm install -g @peerbit/server 8 | ``` 9 | 10 | ```sh 11 | peerbit start 12 | ``` 13 | 14 | Run 15 | ```sh 16 | peerbit --help 17 | ``` 18 | for more info 19 | 20 | ## Configure a server 21 | To configure an existing server to run a reachable node, [read this](./custom.md). 22 | 23 | ## Spawning servers with the CLI 24 | You can also spawn servers using the CLI. Read more [here](./automatic.md). 25 | 26 | 27 | -------------------------------------------------------------------------------- /docs/modules/encoding/index.spec.ts: -------------------------------------------------------------------------------- 1 | it("borsh", async () => { 2 | await import("./borsh.js"); 3 | }); 4 | it("json", async () => { 5 | await import("./json.js"); 6 | }); 7 | -------------------------------------------------------------------------------- /docs/modules/encoding/json.ts: -------------------------------------------------------------------------------- 1 | import { 2 | deserialize, 3 | field, 4 | fixedArray, 5 | serialize, 6 | variant, 7 | } from "@dao-xyz/borsh"; 8 | import { randomBytes } from "@peerbit/crypto"; 9 | import assert from "node:assert"; 10 | 11 | interface Message { 12 | title: string; 13 | message: string; 14 | } 15 | 16 | @variant(0) // V0 17 | class Post { 18 | @field({ type: fixedArray("u8", 32) }) // id will always be a Uint8array with size 32 19 | id: Uint8Array; 20 | 21 | @field({ type: "string" }) 22 | private _messageJSON: string; 23 | 24 | private _message: Message; 25 | 26 | constructor(message: Message) { 27 | this.id = randomBytes(32); 28 | this._message = message; 29 | this._messageJSON = JSON.stringify(this._message); 30 | } 31 | 32 | get message(): Message { 33 | return this._message || (this._message = JSON.parse(this._messageJSON)); 34 | } 35 | } 36 | const message = new Post({ 37 | title: "Hello world!", 38 | message: "This is a JSON message", 39 | }); 40 | const bytes = serialize(message); // [0, ... ] will start with 0 because @variant(0) 41 | const post: Post = deserialize(bytes, Post); 42 | assert.equal(post.message.title, "Hello world!"); 43 | -------------------------------------------------------------------------------- /docs/modules/encryption/encrypted-document.spec.ts: -------------------------------------------------------------------------------- 1 | it("encryped-document", async () => { 2 | await import("./encrypted-document.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/modules/encryption/encrypted-log.spec.ts: -------------------------------------------------------------------------------- 1 | it("encrypted-log", async () => { 2 | await import("./encrypted-log.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/modules/program/README.md: -------------------------------------------------------------------------------- 1 | # Programs 2 | You can think of the `program` component as a database definition with all associated logic: Who can append? Who can read? What happens when an entry gets added? 3 | 4 | 5 | In the *future* `program` will more or less behave like a smart contract, with its own runtime, but for now they are simple JavaScript classes that extend the ```Program``` class. 6 | 7 | ## Example 8 | 9 | [definition](./example.ts ':include :fragment=definition') 10 | 11 | 12 | A `program` lets you write a control mechanism for Append-Only logs (which are represented as a [Log](./packages/log). 13 | 14 | 15 | ## Encoding 16 | As you might have seen, the `@field` and `@variant` decorators are used in multiple places. They indicate how the client should serialize/deserialize the databases and content you create. Peerbit uses a serialization format by default called Borsh, which provides similar functionality to Protobuf but is simpler to understand - and the Typescript implementation requires less code than a Protobuf equivalent (and is faster). 17 | 18 | Read more about the encoding [here](./../encoding/encoding.md) 19 | -------------------------------------------------------------------------------- /docs/modules/program/composition/README.md: -------------------------------------------------------------------------------- 1 | # Composition 2 | Programs can be building blocks for others. The [Document store](./packages/programs/data/document) is a program that is tailored for storing and retrieving documents. 3 | 4 | You can include any external program into your program by adding it to your class definition. Below is an example how a forum database could be defined using composition. 5 | 6 | 7 | [composition](./composition.ts ':include') 8 | 9 | Here are a few examples of programs that you can compose your program with: [Document store](./packages/programs/data/document), [Clock service](./packages/programs/clock-service), [Chain agnostic access controller](./packages/programs/acl/identity-access-controller) 10 | -------------------------------------------------------------------------------- /docs/modules/program/composition/composition.spec.ts: -------------------------------------------------------------------------------- 1 | it("composition", async () => { 2 | await import("./composition.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/modules/program/document-store/document-store.spec.ts: -------------------------------------------------------------------------------- 1 | it("document-store", async () => { 2 | await import("./document-store.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/modules/program/document-store/multisig.spec.ts: -------------------------------------------------------------------------------- 1 | it("multisig", async () => { 2 | await import("./multisig.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/modules/program/document-store/replication-degree.spec.ts: -------------------------------------------------------------------------------- 1 | it("replication-degree", async () => { 2 | await import("./replication-degree.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/modules/program/document-store/roles.spec.ts: -------------------------------------------------------------------------------- 1 | it("roles", async () => { 2 | await import("./roles.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/modules/program/rpc/rpc.spec.ts: -------------------------------------------------------------------------------- 1 | it("rpc", async () => { 2 | await import("./rpc.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/modules/program/rpc/rpc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/modules/program/rpc/rpc1.png -------------------------------------------------------------------------------- /docs/modules/program/rpc/rpc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/modules/program/rpc/rpc2.png -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "private": true, 4 | "version": "0.0.0", 5 | "sideEffects": true, 6 | "type": "module", 7 | "files": [ 8 | "src", 9 | "modules", 10 | "examples", 11 | "topics", 12 | "dist", 13 | "!dist/test", 14 | "!**/*.tsbuildinfo" 15 | ], 16 | "scripts": { 17 | "clean": "#not used", 18 | "build": "#not used", 19 | "test": "aegir test -t node", 20 | "lint": "aegir lint" 21 | }, 22 | "license": "MIT", 23 | "localMaintainers": [ 24 | "dao.xyz" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /docs/peerbit-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/peerbit-logo.png -------------------------------------------------------------------------------- /docs/styles.css: -------------------------------------------------------------------------------- 1 | .markdown-section { 2 | padding: 2rem 20px; 3 | } 4 | 5 | /* scrollbar color */ 6 | ::-webkit-scrollbar { 7 | background: var(--mono-shade3) 8 | } 9 | 10 | ::-webkit-scrollbar-thumb { 11 | background: #888; 12 | } -------------------------------------------------------------------------------- /docs/topics/custom-domain/buffer.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/custom-domain/buffer.mp4 -------------------------------------------------------------------------------- /docs/topics/sharding/ca0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/ca0.png -------------------------------------------------------------------------------- /docs/topics/sharding/ca0b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/ca0b.png -------------------------------------------------------------------------------- /docs/topics/sharding/ca1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/ca1.png -------------------------------------------------------------------------------- /docs/topics/sharding/ca2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/ca2.png -------------------------------------------------------------------------------- /docs/topics/sharding/ca3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/ca3.png -------------------------------------------------------------------------------- /docs/topics/sharding/cpu-toggle.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/cpu-toggle.mp4 -------------------------------------------------------------------------------- /docs/topics/sharding/p1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p1.png -------------------------------------------------------------------------------- /docs/topics/sharding/p10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p10.png -------------------------------------------------------------------------------- /docs/topics/sharding/p11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p11.png -------------------------------------------------------------------------------- /docs/topics/sharding/p12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p12.png -------------------------------------------------------------------------------- /docs/topics/sharding/p13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p13.png -------------------------------------------------------------------------------- /docs/topics/sharding/p14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p14.png -------------------------------------------------------------------------------- /docs/topics/sharding/p15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p15.png -------------------------------------------------------------------------------- /docs/topics/sharding/p16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p16.png -------------------------------------------------------------------------------- /docs/topics/sharding/p17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p17.png -------------------------------------------------------------------------------- /docs/topics/sharding/p18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p18.png -------------------------------------------------------------------------------- /docs/topics/sharding/p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p2.png -------------------------------------------------------------------------------- /docs/topics/sharding/p4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p4.png -------------------------------------------------------------------------------- /docs/topics/sharding/p5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p5.png -------------------------------------------------------------------------------- /docs/topics/sharding/p6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p6.png -------------------------------------------------------------------------------- /docs/topics/sharding/p7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p7.png -------------------------------------------------------------------------------- /docs/topics/sharding/p8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p8.png -------------------------------------------------------------------------------- /docs/topics/sharding/p9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/p9.png -------------------------------------------------------------------------------- /docs/topics/sharding/storage-toggle.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/topics/sharding/storage-toggle.mp4 -------------------------------------------------------------------------------- /docs/topics/wallet-integration/README.md: -------------------------------------------------------------------------------- 1 | # Integrating wallets 2 | You can use Web3 Wallets with Peerbit. However todo so you need to implement the Peerbit Identity type which requires the wallets publickey and a signing function. 3 | 4 | 5 | ## Ethers.js Wallet 6 | 7 | See below as an example one how to integrate the `@ethersproject/wallet` 8 | 9 | [ethersproject](./ethersproject.ts ':include') 10 | -------------------------------------------------------------------------------- /docs/topics/wallet-integration/ethersproject.spec.ts: -------------------------------------------------------------------------------- 1 | it("ethersproject", async () => { 2 | await import("./ethersproject.js"); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | // allow top level await 5 | "allowJs": true, 6 | "checkJs": false, 7 | "strict": false, 8 | "experimentalDecorators": true, 9 | /* "emitDecoratorMetadata": true, */ 10 | "strictNullChecks": false, 11 | "allowUnusedLabels": true, 12 | "noUnusedLocals": false, 13 | "outDir": "dist" 14 | }, 15 | "include": ["modules", "topics", "examples"] 16 | } 17 | -------------------------------------------------------------------------------- /docs/videostream.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/docs/videostream.gif -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/proxy/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/proxy/README.md: -------------------------------------------------------------------------------- 1 | # Peerbit Proxy 2 | ## WIP 🚧 3 | A client you can connect to another client remotely, example use-cases 4 | - Running a proxy client in an Iframe and talk to the parent window that runs a real client 5 | - Running a client in a frontend that talks with a real client on a server. -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/proxy/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./client.js"; 2 | export * from "./host.js"; 3 | export * as connection from "./connection.js"; 4 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/proxy/src/indexer.ts: -------------------------------------------------------------------------------- 1 | import { variant } from "@dao-xyz/borsh"; 2 | import { Message } from "./message.js"; 3 | 4 | @variant(11) 5 | export abstract class IndexerMessage extends Message {} 6 | 7 | // TODO 8 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/proxy/src/lifecycle.ts: -------------------------------------------------------------------------------- 1 | import { variant } from "@dao-xyz/borsh"; 2 | import { Message } from "./message.js"; 3 | 4 | @variant(9) 5 | export abstract class LifeCycleMessage extends Message {} 6 | 7 | @variant(0) 8 | export class REQ_Start extends LifeCycleMessage {} 9 | 10 | @variant(1) 11 | export class RESP_Start extends LifeCycleMessage {} 12 | 13 | @variant(2) 14 | export class REQ_Stop extends LifeCycleMessage {} 15 | 16 | @variant(3) 17 | export class RESP_Stop extends LifeCycleMessage {} 18 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/proxy/src/message.ts: -------------------------------------------------------------------------------- 1 | import { field, fixedArray, variant } from "@dao-xyz/borsh"; 2 | import { randomBytes } from "@peerbit/crypto"; 3 | 4 | @variant(0) 5 | export abstract class Message { 6 | @field({ type: fixedArray("u8", 32) }) 7 | messageId: Uint8Array; 8 | 9 | constructor(messageId?: Uint8Array) { 10 | this.messageId = messageId || randomBytes(32); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/proxy/src/native.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | import { Message } from "./message.js"; 3 | 4 | @variant(0) 5 | export abstract class NativeMessage extends Message {} 6 | 7 | @variant(0) 8 | export class RESP_Void extends NativeMessage {} 9 | 10 | @variant(1) 11 | export class RESP_Error extends NativeMessage { 12 | @field({ type: "string" }) 13 | message: string; 14 | 15 | constructor(error: Error) { 16 | super(); 17 | this.message = error.message; 18 | } 19 | 20 | private _error: Error; 21 | get error() { 22 | return this._error || (this._error = new Error(this.message)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/proxy/src/storage.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | import * as api from "@peerbit/any-store-interface/messages"; 3 | import { Message } from "./message.js"; 4 | 5 | export { api }; 6 | @variant(10) 7 | export class StorageMessage extends Message { 8 | @field({ type: api.MemoryRequest }) 9 | message: T; // [] means root, ['x'] means sublevel named 'x' 10 | 11 | constructor(request: T) { 12 | super(); 13 | this.message = request; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/proxy/test/utils.ts: -------------------------------------------------------------------------------- 1 | import type { TypedEventTarget } from "@libp2p/interface"; 2 | import * as connection from "../src/connection.js"; 3 | 4 | export class EventEmitterNode extends connection.MessageNode { 5 | constructor( 6 | readonly eventEmitter: TypedEventTarget<{ 7 | hello: CustomEvent; 8 | data: CustomEvent; 9 | }>, 10 | ) { 11 | super({ 12 | addEventListener: ( 13 | k: K, 14 | fn: any, 15 | ) => { 16 | this.eventEmitter.addEventListener(k, (ev) => { 17 | fn(ev.detail as connection.EventMessages[K]); 18 | }); 19 | }, 20 | dispatchEvent: (msg) => 21 | this.eventEmitter.dispatchEvent( 22 | new CustomEvent(msg.type, { detail: msg }), 23 | ), 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/proxy/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/README.md: -------------------------------------------------------------------------------- 1 | # Peerbit Window Proxy 2 | 3 | TODO description 4 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | dist 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | /test-results/ 27 | /playwright-report/ 28 | /playwright/.cache/ 29 | /child/public/peerbit/ 30 | /parent/public/peerbit/ 31 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/README.md: -------------------------------------------------------------------------------- 1 | # Tests Window proxy 2 | 3 | The test contains an env where a 4 | - Parent, host. Runs a full Peerbit client (with Libp2p) 5 | - A Child window is talking to the parent through a proxy client (through Window PostMessage API) 6 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | dist 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proxy-test-post-message-child", 3 | "private": true, 4 | "version": "0.2.2", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "start": "vite", 9 | "build": "tsc && vite build", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "@peerbit/proxy-window": "*", 16 | "@peerbit/shared-log": "*" 17 | }, 18 | "devDependencies": { 19 | "@types/react": "^18.2.12", 20 | "@types/react-dom": "^18.2.5", 21 | "@vitejs/plugin-react": "^4.2.1", 22 | "vite": "^6.0.6", 23 | "@peerbit/vite": "*" 24 | }, 25 | "browserslist": { 26 | "production": [ 27 | "chrome >= 67", 28 | "edge >= 79", 29 | "firefox >= 68", 30 | "opera >= 54", 31 | "safari >= 14" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Peerbit child", 3 | "name": "Peerbit child", 4 | "icons": [], 5 | "start_url": ".", 6 | "display": "standalone", 7 | "theme_color": "#000000", 8 | "background_color": "#ffffff" 9 | } 10 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/src/db.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | import { Program } from "@peerbit/program"; 3 | import { SharedLog } from "@peerbit/shared-log"; 4 | 5 | @variant("test-log") 6 | export class TestLog extends Program { 7 | @field({ type: SharedLog }) 8 | log: SharedLog; 9 | 10 | constructor() { 11 | super(); 12 | this.log = new SharedLog({ id: new Uint8Array(32) }); 13 | } 14 | 15 | async open(args?: any): Promise { 16 | return this.log.open(args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { App } from "./App"; 4 | import "./index.css"; 5 | 6 | const root = ReactDOM.createRoot( 7 | document.getElementById("root") as HTMLElement, 8 | ); 9 | root.render( 10 | 11 | 12 | , 13 | ); 14 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "Es2022"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "es2022", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "experimentalDecorators": true, 17 | "noEmit": true, 18 | "jsx": "react-jsx" 19 | }, 20 | "include": ["src"], 21 | "references": [ 22 | { 23 | "path": "./tsconfig.node.json" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "es2022", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/child/vite.config.ts: -------------------------------------------------------------------------------- 1 | import peerbit from "@peerbit/vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react(), peerbit()], 8 | optimizeDeps: { 9 | esbuildOptions: { 10 | target: "esnext", 11 | }, 12 | }, 13 | build: { 14 | target: "esnext", 15 | }, 16 | server: { 17 | port: 5201, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proxy-test-post-message", 3 | "private": true, 4 | "version": "0.2.2", 5 | "type": "module", 6 | "dependencies": {}, 7 | "browserslist": { 8 | "production": [ 9 | "chrome >= 67", 10 | "edge >= 79", 11 | "firefox >= 68", 12 | "opera >= 54", 13 | "safari >= 14" 14 | ], 15 | "development": [ 16 | "last 1 chrome version", 17 | "last 1 firefox version", 18 | "last 1 safari version" 19 | ] 20 | }, 21 | "scripts": { 22 | "test": "playwright test" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | /public/peerbit 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | dist 16 | 17 | # misc 18 | .DS_Store 19 | .env.local 20 | .env.development.local 21 | .env.test.local 22 | .env.production.local 23 | 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proxy-test-post-message-parent", 3 | "private": true, 4 | "version": "0.2.2", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "start": "vite", 9 | "build": "tsc && vite build", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "peerbit": "*", 16 | "@peerbit/proxy-window": "*" 17 | }, 18 | "devDependencies": { 19 | "@types/react": "^18.2.12", 20 | "@types/react-dom": "^18.2.5", 21 | "@vitejs/plugin-react": "^4.2.1", 22 | "@peerbit/vite": "*", 23 | "vite": "^6.0.6" 24 | }, 25 | "browserslist": { 26 | "production": [ 27 | "chrome >= 67", 28 | "edge >= 79", 29 | "firefox >= 68", 30 | "opera >= 54", 31 | "safari >= 14" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Peerbit node", 3 | "name": "Peerbit node", 4 | "icons": [], 5 | "start_url": ".", 6 | "display": "standalone", 7 | "theme_color": "#000000", 8 | "background_color": "#ffffff" 9 | } 10 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { createHost } from "@peerbit/proxy-window"; 2 | import { Peerbit } from "peerbit"; 3 | import { useEffect, useState } from "react"; 4 | 5 | const hostClient = await Peerbit.create({ directory: "hello" }); 6 | const proxy = await createHost(hostClient, "*"); 7 | 8 | if (hostClient.services.pubsub.dispatchEventOnSelfPublish !== true) { 9 | throw new Error( 10 | "Expected hostClient.services.pubsub.dispatchEventOnSelfPublish to be true", 11 | ); 12 | } 13 | 14 | export const App = () => { 15 | const queryParameters = new URLSearchParams(window.location.search); 16 | const [frames, setFrames] = useState(0); 17 | useEffect(() => { 18 | setFrames(Number(queryParameters.get("frames")) || 0); 19 | }, []); 20 | return ( 21 |
22 | {Array.from(Array(frames), (_e, i) => { 23 | return ( 24 | 30 | ); 31 | })} 32 |
33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { App } from "./App"; 4 | import "./index.css"; 5 | 6 | const root = ReactDOM.createRoot( 7 | document.getElementById("root") as HTMLElement, 8 | ); 9 | root.render( 10 | 11 | 12 | , 13 | ); 14 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "Es2022"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "es2022", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "experimentalDecorators": true, 17 | "noEmit": true, 18 | "jsx": "react-jsx" 19 | }, 20 | "include": ["src"], 21 | "references": [ 22 | { 23 | "path": "./tsconfig.node.json" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "es2022", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/parent/vite.config.ts: -------------------------------------------------------------------------------- 1 | import peerbit from "@peerbit/vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | import includeAssetsPlugin from "./../plugin.js"; 5 | 6 | const wasmContentTypePlugin = { 7 | name: "wasm-content-type-plugin", 8 | configureServer(server) { 9 | server.middlewares.use((req, res, next) => { 10 | if (req.url.endsWith(".wasm")) { 11 | res.setHeader("Content-Type", "application/wasm"); 12 | } 13 | next(); 14 | }); 15 | }, 16 | }; 17 | 18 | export default defineConfig({ 19 | plugins: [ 20 | react(), 21 | /* wasmContentTypePlugin, 22 | includeAssetsPlugin({ 23 | assets: [ 24 | { 25 | src: "../../../../../../../node_modules/@peerbit/any-store-opfs/dist/peerbit", 26 | dest: "peerbit/", 27 | }, 28 | { 29 | src: "../../../../../../../node_modules/@peerbit/indexer-sqlite3/dist/peerbit", 30 | dest: "peerbit/", 31 | }, 32 | ], 33 | }), */ 34 | peerbit(), 35 | ], 36 | optimizeDeps: { 37 | /* exclude: ['@sqlite.org/sqlite-wasm', '@peerbit/any-store', '@peerbit/any-store-opfs'], */ 38 | esbuildOptions: { 39 | target: "esnext", 40 | }, 41 | }, 42 | build: { 43 | target: "esnext", 44 | }, 45 | server: { 46 | port: 5202, 47 | }, 48 | }); 49 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/plugin.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | 4 | export default function copyToPublicPlugin(options) { 5 | return { 6 | name: "copy-to-public", 7 | buildStart() { 8 | if (options && options.assets) { 9 | options.assets.forEach(({ src, dest }) => { 10 | const sourcePath = path.resolve(src); 11 | const destinationPath = path.resolve(process.cwd(), "public", dest); 12 | 13 | copyAssets(sourcePath, destinationPath); 14 | }); 15 | } 16 | }, 17 | }; 18 | } 19 | 20 | function copyAssets(srcPath, destPath) { 21 | if (fs.statSync(srcPath).isDirectory()) { 22 | // Ensure the directory exists in the public folder 23 | fs.mkdirSync(destPath, { recursive: true }); 24 | 25 | // Copy each file/directory inside the current directory 26 | fs.readdirSync(srcPath).forEach((file) => { 27 | const srcFilePath = path.join(srcPath, file); 28 | const destFilePath = path.join(destPath, file); 29 | copyAssets(srcFilePath, destFilePath); // Recursion for directories 30 | }); 31 | } else { 32 | // Ensure the destination directory exists 33 | fs.mkdirSync(path.dirname(destPath), { recursive: true }); 34 | 35 | // Copy the file 36 | fs.copyFileSync(srcPath, destPath); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/e2e/browser/tests/iframe.browser.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "@playwright/test"; 2 | 3 | test.describe("iframe", () => { 4 | test("appends cross frames", async ({ page }) => { 5 | let frames = 5; 6 | await page.goto("http://localhost:5202/?frames=" + frames); 7 | const locator = await page.getByTestId("pb0"); 8 | await locator.waitFor({ state: "visible" }); 9 | const iframe = page.frameLocator("#pb0"); 10 | const counter = await iframe.getByTestId("counter"); 11 | await counter.waitFor({ state: "visible" }); 12 | await expect(counter).toHaveText(String(frames), { timeout: 5000 }); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/clients/peerbit-proxy/window/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/README.md: -------------------------------------------------------------------------------- 1 | # Server node 2 | 3 | This foler contains a server CLI utility that allows you to start, manage and spawn server nodes. 4 | 5 | See documentation at [peerbit.org](https://peerbit.org/#/modules/deploy/) 6 | 7 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | dist 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/README.md: -------------------------------------------------------------------------------- 1 | # Node dashboard 2 | 3 | # 🚧 WIP 🚧 -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 25 | Peerbit 26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "0.2.2", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "start": "vite", 9 | "build": "tsc && vite build", 10 | "preview": "vite preview", 11 | "test": "" 12 | }, 13 | "dependencies": { 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0", 16 | "@emotion/react": "^11.10.5", 17 | "@emotion/styled": "^11.10.5", 18 | "@mui/material": "^5.10.13", 19 | "@peerbit/server": "*" 20 | }, 21 | "devDependencies": { 22 | "@types/react": "^18.2.12", 23 | "@types/react-dom": "^18.2.5", 24 | "@vitejs/plugin-react": "^4.2.1", 25 | "vite": "^6.0.6" 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | "chrome >= 67", 30 | "edge >= 79", 31 | "firefox >= 68", 32 | "opera >= 54", 33 | "safari >= 14" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/packages/clients/peerbit-server/frontend/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/packages/clients/peerbit-server/frontend/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/packages/clients/peerbit-server/frontend/public/favicon-16x16.png -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/packages/clients/peerbit-server/frontend/public/favicon-32x32.png -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/packages/clients/peerbit-server/frontend/public/favicon.ico -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Peerbit node", 3 | "name": "Peerbit node", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "/android-chrome-192x192.png", 12 | "sizes": "192x192", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "/android-chrome-512x512.png", 17 | "sizes": "512x512", 18 | "type": "image/png" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { App } from "./App"; 4 | import "./index.css"; 5 | 6 | const root = ReactDOM.createRoot( 7 | document.getElementById("root") as HTMLElement, 8 | ); 9 | root.render( 10 | 11 | 12 | , 13 | ); 14 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "Es2022"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": false, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "es2022", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [ 21 | { 22 | "path": "./tsconfig.node.json" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "es2022", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from "@vitejs/plugin-react"; 2 | import { defineConfig } from "vite"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | optimizeDeps: { 8 | esbuildOptions: { 9 | target: "esnext", 10 | }, 11 | }, 12 | build: { 13 | target: "esnext", 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/.gitignore: -------------------------------------------------------------------------------- 1 | lib 2 | build 3 | _work.json -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/.prettierignore: -------------------------------------------------------------------------------- 1 | lib 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/aws.browser.ts: -------------------------------------------------------------------------------- 1 | // Unsupported 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/bin.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { cli } from "./cli.js"; 3 | 4 | try { 5 | await cli(); 6 | } catch (error: any) { 7 | throw new Error("Unexpected error: " + error?.message); 8 | } 9 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/config.browser.ts: -------------------------------------------------------------------------------- 1 | /// Not supported 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/docker.browser.ts: -------------------------------------------------------------------------------- 1 | // Unsupported 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./server.js"; 2 | export * from "./routes.js"; 3 | export * from "./client.js"; 4 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/remotes.browser.ts: -------------------------------------------------------------------------------- 1 | // Not supported 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/routes.ts: -------------------------------------------------------------------------------- 1 | export const getPort = (protocol: string) => { 2 | if (protocol === "https:") { 3 | return REMOTE_API_PORT; 4 | } 5 | 6 | if (protocol === "http:") { 7 | return LOCAL_API_PORT; 8 | } 9 | 10 | throw new Error("Unsupported protocol: " + protocol); 11 | }; 12 | export const REMOTE_API_PORT = 9002; 13 | export const LOCAL_API_PORT = 8082; 14 | export const TRUST_PATH = "/trust"; 15 | export const PEER_ID_PATH = "/peer/id"; 16 | export const ADDRESS_PATH = "/peer/address"; 17 | export const PROGRAM_PATH = "/program"; 18 | export const PROGRAMS_PATH = "/programs"; 19 | export const PROGRAM_VARIANTS_PATH = "/program/variants"; 20 | export const INSTALL_PATH = "/install"; 21 | export const BOOTSTRAP_PATH = "/network/bootstrap"; 22 | export const RESTART_PATH = "/restart"; 23 | export const TERMINATE_PATH = "/terminate"; 24 | export const STOP_PATH = "/path"; 25 | export const LOG_PATH = "/log"; 26 | export const VERSIONS_PATH = "/versions"; 27 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/server.browser.ts: -------------------------------------------------------------------------------- 1 | // Not supported 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/trust.browser.ts: -------------------------------------------------------------------------------- 1 | // Not supported 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/trust.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | 3 | export class Trust { 4 | trusted: string[]; 5 | constructor(readonly path: string) { 6 | if (fs.existsSync(path)) { 7 | this.trusted = JSON.parse( 8 | fs.readFileSync(path).toString("utf-8"), 9 | ) as string[]; 10 | } else { 11 | this.trusted = []; 12 | } 13 | } 14 | 15 | save() { 16 | fs.writeFileSync(this.path, JSON.stringify(this.trusted)); 17 | } 18 | 19 | isTrusted(hashcode: string) { 20 | return this.trusted.includes(hashcode); 21 | } 22 | 23 | add(key: string) { 24 | if (this.isTrusted(key)) { 25 | return; 26 | } 27 | this.trusted.push(key); 28 | this.save(); 29 | } 30 | 31 | remove(hashcode: string) { 32 | const existing = this.trusted.findIndex((x) => (x = hashcode)); 33 | if (existing >= 0) { 34 | this.trusted.splice(existing, 1); 35 | return true; 36 | } 37 | return false; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface StartByVariant { 2 | variant: string; 3 | } 4 | export interface StartByBase64 { 5 | base64: string; 6 | } 7 | export interface AnyArgs { 8 | [key: string]: any; // Allow extra generic properties 9 | } 10 | export type StartProgram = (StartByVariant | StartByBase64) & AnyArgs; 11 | 12 | export interface InstallWithTGZ { 13 | type: "tgz"; 14 | name: string; 15 | base64: string; 16 | } 17 | 18 | export interface InstallWithNPM { 19 | type: "npm"; 20 | name: string; 21 | } 22 | 23 | export type InstallDependency = InstallWithTGZ | InstallWithNPM; 24 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/test/client.spec.ts: -------------------------------------------------------------------------------- 1 | import { AnyBlockStore } from "@peerbit/blocks"; 2 | import { Ed25519Keypair } from "@peerbit/crypto"; 3 | import { type ProgramClient } from "@peerbit/program"; 4 | import { expect } from "chai"; 5 | import { create } from "../src/peerbit.js"; 6 | 7 | describe("client", () => { 8 | let client: ProgramClient; 9 | afterEach(async () => { 10 | await client?.stop(); 11 | }); 12 | it("default config will relay messages", async () => { 13 | client = await create({ 14 | keypair: await Ed25519Keypair.create(), 15 | directory: "./tmp/server-node/client/" + new Date(), 16 | listenPort: 9123, 17 | }); 18 | expect( 19 | (client.services.blocks as any)["remoteBlocks"].localStore, 20 | ).to.be.instanceOf(AnyBlockStore); 21 | expect((client.services.blocks as any)["canRelayMessage"]).equal(true); 22 | expect((client.services.pubsub as any)["canRelayMessage"]).equal(true); 23 | expect((client.services as any)["relay"]).to.exist; 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/test/config.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { getPackageName } from "../src/config.js"; 3 | 4 | describe("tgz", () => { 5 | it("can get package.json name", async () => { 6 | const pathLib = await import("path"); 7 | const urlLib = await import("url"); 8 | const filename = urlLib.fileURLToPath(import.meta.url); 9 | const dirname = pathLib.dirname(filename); 10 | 11 | expect(await getPackageName(pathLib.join(dirname, "/test.tgz"))).equal( 12 | "@peerbit/test-lib", 13 | ); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/test/launch.spec.ts: -------------------------------------------------------------------------------- 1 | describe("spawn", () => { 2 | it("no-test", () => {}); 3 | /* it("launch and stop", async () => { 4 | const results = await launchNodes({ 5 | email: "marcus@dao.xyz", 6 | count: 1, 7 | namePrefix: "test-counter", 8 | grantAccess: [await (await Ed25519Keypair.create()).publicKey.toPeerId()] 9 | }); 10 | const domain = await waitForDomain(results[0].publicIp); 11 | const client = await createClient(await Ed25519Keypair.create(), { 12 | address: domain, 13 | origin: { 14 | type: "aws", 15 | instanceId: results[0].instanceId, 16 | region: "us-east-1", 17 | }, 18 | }); 19 | await client.terminate(); 20 | }); */ 21 | }); 22 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/test/test.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/packages/clients/peerbit-server/node/test/test.tgz -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/test/utils.ts: -------------------------------------------------------------------------------- 1 | import path, { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | 4 | // eslint-disable-next-line @typescript-eslint/naming-convention 5 | export const __dirname = dirname(fileURLToPath(import.meta.url)); 6 | export const modulesPath = path.join(__dirname, "./tmp/cli-test/modules"); 7 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "outDir": "dist" 7 | }, 8 | "include": ["src", "test"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/test-lib/.gitignore: -------------------------------------------------------------------------------- 1 | lib 2 | build 3 | _work.json -------------------------------------------------------------------------------- /packages/clients/peerbit-server/test-lib/.prettierignore: -------------------------------------------------------------------------------- 1 | lib 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/test-lib/src/index.ts: -------------------------------------------------------------------------------- 1 | import { field, variant, vec } from "@dao-xyz/borsh"; 2 | import { type PeerId } from "@libp2p/interface"; 3 | import { Ed25519PublicKey, PublicSignKey } from "@peerbit/crypto"; 4 | import { Program } from "@peerbit/program"; 5 | import { DString } from "@peerbit/string"; 6 | 7 | @variant("permissioned_string") 8 | export class PermissionedString extends Program { 9 | @field({ type: DString }) 10 | _store: DString; 11 | 12 | @field({ type: vec(PublicSignKey) }) 13 | trusted: PublicSignKey[]; 14 | 15 | constructor(properties?: { 16 | store?: DString; 17 | trusted: (PublicSignKey | PeerId)[]; 18 | }) { 19 | super(); 20 | this._store = properties?.store || new DString({}); 21 | this.trusted = 22 | properties?.trusted.map((x) => 23 | x instanceof PublicSignKey ? x : Ed25519PublicKey.fromPeerId(x), 24 | ) || []; 25 | } 26 | 27 | get store(): DString { 28 | return this._store; 29 | } 30 | 31 | async open(_args?: { log?: boolean }): Promise { 32 | await this._store.open(); 33 | } 34 | 35 | isTrusted(keyHash: string): boolean | Promise { 36 | for (const t of this.trusted) { 37 | if (t.hashcode() == keyHash) { 38 | return true; 39 | } 40 | } 41 | return false; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/test-lib/test/cli.spec.ts: -------------------------------------------------------------------------------- 1 | // This more like a playground as of now 2 | // No real tests yet, 3 | // But there are ways here to generate base64 string for programs 4 | import { deserialize, serialize } from "@dao-xyz/borsh"; 5 | import { Program, type ProgramClient } from "@peerbit/program"; 6 | import { DString } from "@peerbit/string"; 7 | import { TestSession } from "@peerbit/test-utils"; 8 | import { PermissionedString } from "../src/index.js"; 9 | 10 | describe("server", () => { 11 | let session: TestSession, peer: ProgramClient; 12 | 13 | before(async () => { 14 | session = await TestSession.connected(1, { 15 | directory: "./tmp/peerbit/" + +new Date(), 16 | }); 17 | peer = session.peers[0]; 18 | }); 19 | 20 | after(async () => { 21 | await peer.stop(); 22 | await session.stop(); 23 | }); 24 | 25 | it("_", async () => { 26 | const program = new PermissionedString({ 27 | store: new DString({}), 28 | trusted: [peer.identity.publicKey], 29 | }); 30 | const base54 = Buffer.from(serialize(program)).toString("base64"); 31 | deserialize(Buffer.from(base54, "base64"), Program); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/clients/peerbit-server/test-lib/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/clients/peerbit/.aegir.js: -------------------------------------------------------------------------------- 1 | import findUp from "find-up"; 2 | import path from "path"; 3 | 4 | const root = path.dirname(findUp.sync(".git", { type: "directory" })); 5 | export default { 6 | // test cmd options 7 | build: { 8 | bundle: true, 9 | bundlesize: false, 10 | bundlesizeMax: "100kB", 11 | types: true, 12 | }, 13 | test: { 14 | build: true, 15 | runner: "node", 16 | target: ["node", "browser", "webworker"], 17 | watch: false, 18 | files: [], 19 | timeout: 60000, 20 | grep: "", 21 | bail: false, 22 | debug: true, 23 | progress: false, 24 | cov: false, 25 | covTimeout: 60000, 26 | browser: { 27 | debug: true, 28 | config: { 29 | debug: true, 30 | assets: [ 31 | "../../../node_modules/@peerbit/any-store-opfs/dist", 32 | "../../../node_modules/@peerbit/indexer-sqlite3/dist", 33 | "../../../node_modules/@sqlite.org/sqlite-wasm/sqlite-wasm/jswasm", 34 | "./dist", 35 | ], 36 | buildConfig: { 37 | conditions: ["production"], 38 | }, 39 | }, 40 | }, 41 | before: () => { 42 | return { 43 | env: { TS_NODE_PROJECT: path.join(root, "tsconfig.test.json") }, 44 | }; 45 | }, 46 | }, 47 | }; 48 | -------------------------------------------------------------------------------- /packages/clients/peerbit/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/clients/peerbit/benchmark/start-stop.ts: -------------------------------------------------------------------------------- 1 | import B from "benchmark"; 2 | import { Peerbit } from "../src/peer.js"; 3 | 4 | // Run with "node --loader ts-node/esm ./benchmark/start-stop.ts" 5 | 6 | // start and stop x 91.15 ops/sec ±0.95% (87 runs sampled) 7 | const suite = new B.Suite(); 8 | suite 9 | .add("start and stop", { 10 | fn: async (deferred: any) => { 11 | const node = await Peerbit.create(); 12 | await node.start(); 13 | await node.stop(); 14 | deferred.resolve(); 15 | }, 16 | defer: true, 17 | }) 18 | .on("cycle", (event: any) => { 19 | console.log(String(event.target)); 20 | }) 21 | .run({ async: true }); 22 | -------------------------------------------------------------------------------- /packages/clients/peerbit/src/bootstrap.ts: -------------------------------------------------------------------------------- 1 | export const resolveBootstrapAddresses = async ( 2 | v: string = "4", 3 | ): Promise => { 4 | // Bootstrap addresses for network 5 | return ( 6 | await ( 7 | await fetch( 8 | `https://bootstrap.peerbit.org/bootstrap${v ? "-" + v : ""}.env`, 9 | ) 10 | ).text() 11 | ) 12 | .split(/\r?\n/) 13 | .filter((x) => x.length > 0); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/clients/peerbit/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./peer.js"; 2 | export { 3 | createLibp2pExtended, 4 | type Libp2pExtendServices, 5 | type Libp2pExtended, 6 | type Libp2pCreateOptions, 7 | type Libp2pCreateOptionsWithServices, 8 | } from "./libp2p.js"; 9 | -------------------------------------------------------------------------------- /packages/clients/peerbit/src/transports.browser.ts: -------------------------------------------------------------------------------- 1 | import { circuitRelayTransport } from "@libp2p/circuit-relay-v2"; 2 | import { webRTC } from "@libp2p/webrtc"; 3 | import { webSockets } from "@libp2p/websockets"; 4 | import { all } from "@libp2p/websockets/filters"; 5 | 6 | export const transports = () => [ 7 | webSockets({ filter: all }), 8 | circuitRelayTransport({ 9 | reservationCompletionTimeout: 5000, 10 | }), 11 | webRTC({}), 12 | ]; 13 | 14 | export const relay = () => undefined as any; 15 | 16 | export const listen: () => string[] | undefined = () => [ 17 | "/webrtc", 18 | "/p2p-circuit", 19 | ]; 20 | -------------------------------------------------------------------------------- /packages/clients/peerbit/src/transports.ts: -------------------------------------------------------------------------------- 1 | import { 2 | circuitRelayServer, 3 | circuitRelayTransport, 4 | } from "@libp2p/circuit-relay-v2"; 5 | import { tcp } from "@libp2p/tcp"; 6 | import { webSockets } from "@libp2p/websockets"; 7 | import { all } from "@libp2p/websockets/filters"; 8 | 9 | export const transports = () => [ 10 | webSockets({ filter: all }), 11 | circuitRelayTransport({ 12 | reservationCompletionTimeout: 5000, 13 | }), 14 | tcp(), 15 | ]; 16 | export const relay = () => 17 | // applyDefaultLimit: false because of https://github.com/libp2p/js-libp2p/issues/2622 18 | circuitRelayServer({ 19 | reservations: { applyDefaultLimit: false, maxReservations: 1000 }, 20 | }); 21 | 22 | export const listen: () => string[] | undefined = () => [ 23 | "/ip4/127.0.0.1/tcp/0", 24 | "/ip4/127.0.0.1/tcp/0/ws", 25 | "/p2p-circuit", 26 | ]; 27 | -------------------------------------------------------------------------------- /packages/clients/peerbit/test/bootstrap.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { Peerbit } from "../src/peer.js"; 3 | 4 | describe("bootstrap", () => { 5 | let peer: Peerbit; 6 | 7 | beforeEach(async () => { 8 | peer = await Peerbit.create(); 9 | }); 10 | 11 | afterEach(async () => { 12 | await peer.stop(); 13 | }); 14 | 15 | it("remote", async () => { 16 | await peer.bootstrap(); 17 | expect(peer.libp2p.services.pubsub.peers.size).greaterThan(0); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/clients/peerbit/test/indexer.spec.ts: -------------------------------------------------------------------------------- 1 | import { HashmapIndices, create } from "@peerbit/indexer-simple"; 2 | import { SQLiteIndices } from "@peerbit/indexer-sqlite3"; 3 | import { expect } from "chai"; 4 | import { Peerbit } from "../src"; 5 | 6 | describe("indexer", () => { 7 | let client: Peerbit; 8 | afterEach(async () => { 9 | await client?.stop(); 10 | }); 11 | 12 | it("sqlite indexer by default", async () => { 13 | client = await Peerbit.create(); 14 | expect(client.indexer).to.be.instanceOf(SQLiteIndices); 15 | }); 16 | 17 | it("can provide custom indexer", async () => { 18 | client = await Peerbit.create({ indexer: create }); 19 | expect(client.indexer).to.be.instanceOf(HashmapIndices); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/clients/peerbit/test/libp2p.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import sodium from "libsodium-wrappers"; 3 | import { createLibp2pExtended } from "../src/libp2p.js"; 4 | 5 | it("starts", async () => { 6 | await sodium.ready; // Some of the modules depends on sodium to be readyy 7 | const node = await createLibp2pExtended(); 8 | await node.start(); 9 | // if node we expect 2 addresse if browser 0 10 | 11 | if (typeof window === "undefined") { 12 | expect(node.getMultiaddrs()).to.have.length(2); 13 | } else { 14 | expect(node.getMultiaddrs()).to.have.length(0); 15 | } 16 | 17 | expect(node.services.pubsub).to.exist; 18 | expect(node.services.blocks).to.exist; 19 | await node.stop(); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/clients/peerbit/test/node.js: -------------------------------------------------------------------------------- 1 | import "./create.js"; 2 | -------------------------------------------------------------------------------- /packages/clients/peerbit/test/start-stop.spec.ts: -------------------------------------------------------------------------------- 1 | import { variant } from "@dao-xyz/borsh"; 2 | import { generateKeyPair } from "@libp2p/crypto/keys"; 3 | import { Program } from "@peerbit/program"; 4 | import { expect } from "chai"; 5 | import { Peerbit } from "../src/peer.js"; 6 | 7 | @variant("test-start-stop") 8 | class TestP extends Program { 9 | async open(_args?: any): Promise { 10 | await (await this.node.storage.sublevel("test")).open(); 11 | } 12 | } 13 | describe("start-stop", () => { 14 | let client: Peerbit; 15 | 16 | after(async () => { 17 | await client.stop(); 18 | }); 19 | it("can create with peerId", async () => { 20 | const privateKey = await generateKeyPair("Ed25519"); 21 | client = await Peerbit.create({ 22 | libp2p: { privateKey }, 23 | }); 24 | expect(client.peerId.publicKey!.equals(privateKey.publicKey)).to.be.true; 25 | const addressA = (await client.open(new TestP())).address; 26 | 27 | await client.stop(); 28 | await client.start(); 29 | const addressB = (await client.open(new TestP())).address; 30 | 31 | expect(addressA).equal(addressB); 32 | expect(addressA).to.exist; 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /packages/clients/peerbit/test/subprogram.spec.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | import { Program } from "@peerbit/program"; 3 | import { Peerbit } from "../src/peer.js"; 4 | 5 | @variant("child") 6 | class SubProgram extends Program { 7 | constructor() { 8 | super(); 9 | } 10 | async open() {} 11 | } 12 | 13 | @variant("parent") 14 | class ParentProgram extends Program { 15 | @field({ type: SubProgram }) 16 | subprogram: SubProgram; 17 | 18 | constructor() { 19 | super(); 20 | this.subprogram = new SubProgram(); 21 | } 22 | async open(): Promise { 23 | await this.node.open(this.subprogram, { parent: this }); 24 | } 25 | } 26 | 27 | describe("subprogram", () => { 28 | let client: Peerbit; 29 | beforeEach(async () => { 30 | client = await Peerbit.create(); 31 | }); 32 | 33 | afterEach(async () => { 34 | await client.stop(); 35 | }); 36 | 37 | it("subprogram can open on parent open", async () => { 38 | // if this never resolved then we have a deadlock 39 | await client.open(new ParentProgram()); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /packages/clients/peerbit/test/utils/event-store.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | import { randomBytes, sha256Base64Sync } from "@peerbit/crypto"; 3 | import { Program } from "@peerbit/program"; 4 | 5 | // TODO: generalize the Iterator functions and spin to its own module 6 | export interface Operation { 7 | op: string; 8 | key?: string; 9 | value?: T; 10 | } 11 | 12 | @variant("event_store") 13 | export class EventStore extends Program { 14 | @field({ type: Uint8Array }) 15 | id: Uint8Array; 16 | 17 | log: { hash: string; data: Uint8Array }[]; 18 | 19 | constructor(properties?: { id: Uint8Array }) { 20 | super(); 21 | this.id = properties?.id || randomBytes(32); 22 | this.log = []; 23 | } 24 | 25 | async open() { 26 | return; 27 | } 28 | 29 | add(data: Uint8Array, args: any) { 30 | this.log.push({ hash: sha256Base64Sync(data), data }); 31 | } 32 | 33 | async get(hash: string) { 34 | return this.log.find((x) => x.hash === hash); 35 | } 36 | 37 | async iterator(options?: any) { 38 | return this.log; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/clients/peerbit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test", "benchmark"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/clients/test-utils/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .nyc_output 3 | coverage 4 | dist -------------------------------------------------------------------------------- /packages/clients/test-utils/src/index.ts: -------------------------------------------------------------------------------- 1 | import { TestSession } from "./session.js"; 2 | 3 | export { TestSession }; 4 | -------------------------------------------------------------------------------- /packages/clients/test-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/clients/vite/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .nyc_output 3 | coverage 4 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | dist 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | /public/peerbit/ -------------------------------------------------------------------------------- /packages/clients/vite/e2e/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 25 | Peerbit 26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-plugin-test", 3 | "private": true, 4 | "version": "0.0.1s", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "start": "vite", 9 | "build": "tsc && vite build", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "@peerbit/shared-log": "*" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^18.2.12", 19 | "@types/react-dom": "^18.2.5", 20 | "@vitejs/plugin-react": "^4.2.1", 21 | "vite": "^6.0.6", 22 | "@peerbit/vite": "*" 23 | }, 24 | "browserslist": { 25 | "production": [ 26 | "chrome >= 67", 27 | "edge >= 79", 28 | "firefox >= 68", 29 | "opera >= 54", 30 | "safari >= 14" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Peerbit child", 3 | "name": "Peerbit child", 4 | "icons": [], 5 | "start_url": ".", 6 | "display": "standalone", 7 | "theme_color": "#000000", 8 | "background_color": "#ffffff" 9 | } 10 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/src/db.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | import { Program } from "@peerbit/program"; 3 | import { SharedLog } from "@peerbit/shared-log"; 4 | 5 | @variant("test-log") 6 | export class TestLog extends Program { 7 | @field({ type: SharedLog }) 8 | log: SharedLog; 9 | 10 | constructor() { 11 | super(); 12 | this.log = new SharedLog({ id: new Uint8Array(32) }); 13 | } 14 | 15 | async open(args?: any): Promise { 16 | return this.log.open(args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } -------------------------------------------------------------------------------- /packages/clients/vite/e2e/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { App } from "./App"; 4 | import "./index.css"; 5 | 6 | const root = ReactDOM.createRoot( 7 | document.getElementById("root") as HTMLElement, 8 | ); 9 | root.render( 10 | 11 | 12 | , 13 | ); 14 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "Es2022"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "es2022", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "experimentalDecorators": true, 17 | "noEmit": true, 18 | "jsx": "react-jsx" 19 | }, 20 | "include": ["src", "public"], 21 | "references": [ 22 | { 23 | "path": "./tsconfig.node.json" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "es2022", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/clients/vite/e2e/vite.config.ts: -------------------------------------------------------------------------------- 1 | import peerbit from "@peerbit/vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import { defineConfig } from "vite"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react(), peerbit()], 8 | optimizeDeps: { 9 | esbuildOptions: { 10 | target: "esnext", 11 | }, 12 | }, 13 | build: { 14 | target: "esnext", 15 | }, 16 | server: { 17 | port: 5201, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /packages/clients/vite/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/log/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | ipfs/ 4 | ipfs-log/ 5 | orbitdb/ 6 | dist/*.js.map 7 | examples/browser/bundle.js 8 | test/keystore/ 9 | test-keys/ 10 | test/browser/bundle.js 11 | test/browser/bundle.js.map 12 | ipfs-log-benchmarks/ 13 | examples/browser/bundle.js.map 14 | examples/browser/ipfs.min.js 15 | examples/browser/ipfslog.min.js 16 | .nyc_output 17 | lib -------------------------------------------------------------------------------- /packages/log/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2018 Protocol Labs Inc. 4 | Copyright (c) 2018-2019 Haja Networks Oy 5 | Copyright (c) 2022 dao.xyz 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /packages/log/README.md: -------------------------------------------------------------------------------- 1 | [Forked from](https://github.com/orbitdb/ipfs-log) 2 | 3 | Additional features 4 | + Binary ser/der 5 | + Log "cutting" 6 | + Typescript 7 | + Graph ids (gid) 8 | 9 | Other changes 10 | + Removal of entry refs (improve load speeds can be achieved in other way) 11 | + ESM only -------------------------------------------------------------------------------- /packages/log/benchmark/append.ts: -------------------------------------------------------------------------------- 1 | import { AnyBlockStore } from "@peerbit/blocks"; 2 | import { Ed25519Keypair } from "@peerbit/crypto"; 3 | import { create } from "@peerbit/indexer-sqlite3"; 4 | import * as B from "tinybench"; 5 | import { Log } from "../src/log.js"; 6 | 7 | // Run with "node --loader ts-node/esm ./benchmark/append.ts" 8 | 9 | let log: Log; 10 | let store: AnyBlockStore; 11 | const key = await Ed25519Keypair.create(); 12 | 13 | const close = () => { 14 | return log?.close(); 15 | }; 16 | const reset = async () => { 17 | await close(); 18 | log = new Log(); 19 | store = new AnyBlockStore(); 20 | await log.open(store, key, { indexer: await create() }); 21 | }; 22 | await reset(); 23 | 24 | const suite = new B.Bench({ warmupIterations: 1000, setup: reset }); 25 | await suite 26 | .add("chain", async () => { 27 | await log.append(new Uint8Array([1, 2, 3])); 28 | }) 29 | .add("no-next", async () => { 30 | await log.append(new Uint8Array([1, 2, 3]), { meta: { next: [] } }); 31 | }) 32 | .run(); 33 | 34 | await close(); 35 | console.table(suite.table()); 36 | -------------------------------------------------------------------------------- /packages/log/benchmark/memory/utils.ts: -------------------------------------------------------------------------------- 1 | export type Message = 2 | | { type: "init"; storage: "in-memory" | "disc" } 3 | | { type: "insert"; docs: number; size?: number } 4 | | { type: "done" } 5 | | { type: "ready" }; 6 | -------------------------------------------------------------------------------- /packages/log/src/change.ts: -------------------------------------------------------------------------------- 1 | import type { Entry, ShallowOrFullEntry } from "./entry.js"; 2 | 3 | export type Change = { 4 | added: { head: boolean; entry: Entry }[]; 5 | removed: ShallowOrFullEntry[]; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/log/src/difference.ts: -------------------------------------------------------------------------------- 1 | export const difference = (a: any, b: any, key: string) => { 2 | // Indices for quick lookups 3 | const processed: { [key: string]: any } = {}; 4 | const existing: { [key: string]: any } = {}; 5 | 6 | // Create an index of the first collection 7 | const addToIndex = (e: any) => (existing[key ? e[key] : e] = true); 8 | a.forEach(addToIndex); 9 | 10 | // Reduce to entries that are not in the first collection 11 | const reducer = (res: any, entry: any) => { 12 | const isInFirst = existing[key ? entry[key] : entry] !== undefined; 13 | const hasBeenProcessed = processed[key ? entry[key] : entry] !== undefined; 14 | if (!isInFirst && !hasBeenProcessed) { 15 | res.push(entry); 16 | processed[key ? entry[key] : entry] = true; 17 | } 18 | return res; 19 | }; 20 | 21 | return b.reduce(reducer, []); 22 | }; 23 | -------------------------------------------------------------------------------- /packages/log/src/encoding.ts: -------------------------------------------------------------------------------- 1 | import { type AbstractType, deserialize, serialize } from "@dao-xyz/borsh"; 2 | 3 | export interface Encoding { 4 | encoder: (data: T) => Uint8Array; 5 | decoder: (bytes: Uint8Array) => T; 6 | } 7 | export const NO_ENCODING: Encoding = { 8 | encoder: (obj: Uint8Array) => { 9 | if (obj instanceof Uint8Array === false) { 10 | throw new Error( 11 | "With NO_ENCODING only Uint8arrays are allowed, received: " + 12 | (obj?.["constructor"]?.["name"] || typeof obj), 13 | ); 14 | } 15 | return obj; 16 | }, 17 | decoder: (bytes: Uint8Array) => { 18 | return bytes; 19 | }, 20 | }; 21 | 22 | export const BORSH_ENCODING = (clazz: AbstractType): Encoding => { 23 | return { 24 | decoder: (bytes: Uint8Array) => deserialize(bytes, clazz), 25 | encoder: (data: any) => serialize(data), 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/log/src/entry-create.ts: -------------------------------------------------------------------------------- 1 | import type { Blocks } from "@peerbit/blocks-interface"; 2 | import type { Identity, SignatureWithKey } from "@peerbit/crypto"; 3 | import type { LamportClock as Clock } from "./clock.js"; 4 | import type { Encoding } from "./encoding.js"; 5 | import type { EntryType } from "./entry-type.js"; 6 | import { type EntryEncryption, EntryV0 } from "./entry-v0.js"; 7 | import type { CanAppend, Entry } from "./entry.js"; 8 | import type { SortableEntry } from "./log-sorting.js"; 9 | 10 | export const createEntry = async (properties: { 11 | store: Blocks; 12 | data: T; 13 | meta?: { 14 | clock?: Clock; 15 | gid?: string; 16 | type?: EntryType; 17 | gidSeed?: Uint8Array; 18 | data?: Uint8Array; 19 | next?: SortableEntry[]; 20 | }; 21 | encoding?: Encoding; 22 | canAppend?: CanAppend; 23 | encryption?: EntryEncryption; 24 | identity: Identity; 25 | signers?: (( 26 | data: Uint8Array, 27 | ) => Promise | SignatureWithKey)[]; 28 | }): Promise> => { 29 | return EntryV0.create(properties); 30 | }; 31 | -------------------------------------------------------------------------------- /packages/log/src/entry-type.ts: -------------------------------------------------------------------------------- 1 | export enum EntryType { 2 | APPEND = 0, // Add more data 3 | CUT = 1, // Delete or Create tombstone ... delete all nexts, i 4 | } 5 | -------------------------------------------------------------------------------- /packages/log/src/entry-with-refs.ts: -------------------------------------------------------------------------------- 1 | import type { Entry } from "./entry.js"; 2 | 3 | export interface EntryWithRefs { 4 | entry: Entry; 5 | references: Entry[]; 6 | } 7 | -------------------------------------------------------------------------------- /packages/log/src/find-uniques.ts: -------------------------------------------------------------------------------- 1 | export const findUniques = (value: T[], key?: string): T[] => { 2 | // Create an index of the collection 3 | // TODO fix types. This method is quite ugly, maybe lets remove it altogether 4 | const uniques: { [key: string | number | symbol]: T } = {}; 5 | const get = (key: string | number | symbol) => uniques[key]; 6 | const addToIndex = (e: T) => 7 | (uniques[ 8 | key 9 | ? ((e as any)[key] as string | number | symbol) 10 | : (e as string | number | symbol) 11 | ] = e); 12 | value.forEach(addToIndex); 13 | return Object.keys(uniques).map(get); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/log/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./log.js"; 2 | export * from "./log-sorting.js"; 3 | export * from "./log-errors.js"; 4 | export * from "./snapshot.js"; 5 | export * from "./entry.js"; 6 | export * from "./entry-type.js"; 7 | export * from "./entry-with-refs.js"; 8 | export * from "./entry-shallow.js"; 9 | export * from "./utils.js"; 10 | export * from "./clock.js"; 11 | export * from "./encoding.js"; 12 | export * from "./trim.js"; 13 | export * from "./change.js"; 14 | export * from "./entry-v0.js"; 15 | export * from "./entry-create.js"; 16 | export type { TrimToByteLengthOption, TrimToLengthOption } from "./trim.js"; 17 | -------------------------------------------------------------------------------- /packages/log/src/log-errors.ts: -------------------------------------------------------------------------------- 1 | export const BlockStoreNotDefinedError = () => 2 | new Error("Block store not defined"); 3 | export const LogNotDefinedError = () => new Error("Log instance not defined"); 4 | export const NotALogError = () => 5 | new Error("Given argument is not an instance of Log"); 6 | export const CannotJoinWithDifferentId = () => 7 | new Error("Can't join logs with different IDs"); 8 | export const LtOrLteMustBeStringOrArray = () => 9 | new Error("lt or lte must be a string or array of Entries"); 10 | -------------------------------------------------------------------------------- /packages/log/src/logger.ts: -------------------------------------------------------------------------------- 1 | import pino from "pino"; 2 | 3 | const logger = pino(); 4 | export { logger }; 5 | -------------------------------------------------------------------------------- /packages/log/src/payload.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | import { type Encoding, NO_ENCODING } from "./encoding.js"; 3 | import { equals } from "./utils.js"; 4 | 5 | @variant(0) 6 | export class Payload { 7 | @field({ type: Uint8Array }) 8 | data: Uint8Array; 9 | 10 | encoding: Encoding; 11 | 12 | private _value?: T; 13 | 14 | constructor(props: { data: Uint8Array; value?: T; encoding: Encoding }) { 15 | this.data = props.data; 16 | this._value = props.value; 17 | this.encoding = props?.encoding; 18 | } 19 | 20 | equals(other: Payload): boolean { 21 | return equals(this.data, other.data); 22 | } 23 | 24 | get isDecoded(): boolean { 25 | return this._value != null; 26 | } 27 | 28 | get value(): T { 29 | if (this._value == null) { 30 | throw new Error("Value not decoded. Invoke: .getValue once"); 31 | } 32 | return this._value; 33 | } 34 | getValue(encoding: Encoding = this.encoding || NO_ENCODING): T { 35 | if (this._value !== undefined) { 36 | return this._value; 37 | } 38 | return encoding.decoder(this.data); 39 | } 40 | 41 | get byteLength() { 42 | return this.data.byteLength; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/log/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { equals as uequals } from "uint8arrays"; 2 | 3 | export const equals = (array1?: Uint8Array, array2?: Uint8Array) => { 4 | if (!!array1 !== !!array2) return false; 5 | if (!array1 || !array2) { 6 | return false; 7 | } 8 | return uequals(array1, array2); 9 | }; 10 | 11 | export const max = (...args: T[]) => args.reduce((m, e) => (e > m ? e : m)); 12 | export const min = (...args: T[]) => args.reduce((m, e) => (e < m ? e : m)); 13 | -------------------------------------------------------------------------------- /packages/log/test/drop.spec.ts: -------------------------------------------------------------------------------- 1 | import { AnyBlockStore } from "@peerbit/blocks"; 2 | import { Ed25519Keypair } from "@peerbit/crypto"; 3 | import { expect } from "chai"; 4 | import { Log } from "../src/log.js"; 5 | 6 | describe("drop", () => { 7 | let log: Log; 8 | let store: AnyBlockStore; 9 | beforeEach(async () => { 10 | log = new Log(); 11 | store = new AnyBlockStore(); 12 | await store.start(); 13 | await log.open(store, await Ed25519Keypair.create()); 14 | }); 15 | 16 | afterEach(async () => { 17 | await log.close(); 18 | await store.stop(); 19 | }); 20 | it("drops entries", async () => { 21 | const e0 = await log.append(new Uint8Array([1])); 22 | expect(log.length).equal(1); 23 | let loadedEntry = await store.get(e0.entry.hash); 24 | expect(loadedEntry).to.exist; 25 | await log.drop(); 26 | loadedEntry = await store.get(e0.entry.hash); 27 | expect(loadedEntry).equal(undefined); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/log/test/utils/encoding.ts: -------------------------------------------------------------------------------- 1 | import { type AbstractType, deserialize, serialize } from "@dao-xyz/borsh"; 2 | import stringify from "json-stringify-deterministic"; 3 | import { type Encoding } from "../../src/encoding.js"; 4 | 5 | const encoder = new TextEncoder(); 6 | const decoder = new TextDecoder(); 7 | 8 | export const JSON_ENCODING: Encoding = { 9 | encoder: (obj: any) => { 10 | return new Uint8Array(encoder.encode(stringify(obj))); 11 | }, 12 | decoder: (bytes: Uint8Array) => { 13 | return JSON.parse(decoder.decode(bytes).toString()); 14 | }, 15 | }; 16 | 17 | export const BORSH_ENCODING = (clazz: AbstractType): Encoding => { 18 | return { 19 | decoder: (bytes: Uint8Array) => deserialize(bytes, clazz), 20 | encoder: (data: any) => serialize(data), 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/log/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "noUnusedParameters": false, 7 | "noUnusedLocals": false, 8 | "outDir": "dist", 9 | "checkJs": false 10 | }, 11 | "include": ["src", "test", "benchmark"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/programs/acl/identity-access-controller/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/programs/acl/identity-access-controller/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 dao.xyz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /packages/programs/acl/identity-access-controller/README.md: -------------------------------------------------------------------------------- 1 | # "Chain agnostic" Access Controller 2 | ## 🚧 Experimental state 🚧 3 | 4 | An access controller that supports different layers of control and fallbacks. 5 | 6 | - A store containing ACL information, for example what public key can read and write 7 | - A distributed relation store that lets you use linked devices to get access 8 | - A fallback trusted network access controller that lets you have access if you are trusted by the root trust identity 9 | 10 | 11 | As of now, go through the tests for documentation. 12 | -------------------------------------------------------------------------------- /packages/programs/acl/identity-access-controller/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./access.js"; 2 | export * from "./acl-db.js"; 3 | export * from "./condition.js"; 4 | -------------------------------------------------------------------------------- /packages/programs/acl/identity-access-controller/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/programs/acl/trusted-network/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/programs/acl/trusted-network/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 dao.xyz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /packages/programs/acl/trusted-network/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./controller.js"; 2 | export * from "./identity-graph.js"; 3 | -------------------------------------------------------------------------------- /packages/programs/acl/trusted-network/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/programs/clock-service/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/programs/clock-service/README.md: -------------------------------------------------------------------------------- 1 | # ClockService 2 | 3 | ## 🚧 Experimental state 🚧 4 | This module can sign entries to verify that their timestamps are set correctly. 5 | 6 | See the [test](./src/__tests__/index.test.ts) for examples. 7 | 8 | Nodes running this program will sign entries if their timestamp is not too far from "now". 9 | Hence, only use this program with an identity dedicated for this job since peers can send any entry to be signed (i.e. use dedicated nodes for this) 10 | -------------------------------------------------------------------------------- /packages/programs/clock-service/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./controller.js"; 2 | -------------------------------------------------------------------------------- /packages/programs/clock-service/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/programs/data/document/document/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/programs/data/document/document/benchmark/memory/utils.ts: -------------------------------------------------------------------------------- 1 | export type Message = 2 | | { type: "init"; storage: "in-memory" | "disc" } 3 | | { type: "insert"; docs: number; size?: number } 4 | | { type: "done" } 5 | | { type: "ready" }; 6 | -------------------------------------------------------------------------------- /packages/programs/data/document/document/src/borsh.ts: -------------------------------------------------------------------------------- 1 | import { getSchema } from "@dao-xyz/borsh"; 2 | 3 | export const copySerialization = (sourceClazz: any, targetClazz: any) => { 4 | const copiedFromAlready: any[] = targetClazz["__copiedFrom"] || []; 5 | if (copiedFromAlready?.includes(sourceClazz)) { 6 | return; 7 | } 8 | 9 | copiedFromAlready.push(sourceClazz); 10 | targetClazz["__copiedFrom"] = copiedFromAlready; 11 | 12 | const targetSchema = getSchema(targetClazz); 13 | const sourceSchema = getSchema(sourceClazz); 14 | 15 | targetSchema.fields = [...sourceSchema.fields, ...targetSchema.fields]; 16 | targetSchema.variant = sourceSchema.variant; 17 | targetSchema.getDependencies = 18 | sourceSchema.getDependencies.bind(sourceSchema); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/programs/data/document/document/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const MAX_BATCH_SIZE = 5e6; 2 | -------------------------------------------------------------------------------- /packages/programs/data/document/document/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "@peerbit/indexer-interface"; 2 | export * from "@peerbit/document-interface"; 3 | export * from "./program.js"; 4 | export type { 5 | CanRead, 6 | CanSearch, 7 | DocumentIndex, 8 | WithContext, 9 | WithIndexedContext, 10 | OpenOptions, 11 | QueryOptions, 12 | RemoteQueryOptions, 13 | ResultsIterator, 14 | SearchOptions, 15 | TransformOptions, 16 | TransformerAsConstructor, 17 | TransformerAsFunction, 18 | ValueTypeFromRequest, 19 | } from "./search.js"; 20 | export { coerceWithContext } from "./search.js"; 21 | export * from "./operation.js"; 22 | export { MAX_BATCH_SIZE as MAX_DOCUMENT_SIZE } from "./constants.js"; 23 | export { ClosedError } from "@peerbit/program"; 24 | export { 25 | type CustomDocumentDomain, 26 | createDocumentDomain, 27 | createDocumentDomainFromProperty, 28 | } from "./domain.js"; 29 | -------------------------------------------------------------------------------- /packages/programs/data/document/document/test/types.spec.ts: -------------------------------------------------------------------------------- 1 | import { type ResultsIterator } from "../src/index.js"; 2 | 3 | describe("types", () => { 4 | it("ResultsIterator", () => { 5 | // @ts-expect-error unused 6 | const iterator: ResultsIterator = { 7 | next: async (count: number) => { 8 | return [] as any[]; 9 | }, 10 | done: () => true, 11 | close: async () => {}, 12 | }; 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/programs/data/document/document/test/utils.ts: -------------------------------------------------------------------------------- 1 | import type { ProgramClient } from "@peerbit/program"; 2 | import type { DirectSub } from "@peerbit/pubsub"; 3 | import { delay } from "@peerbit/time"; 4 | 5 | export const slowDownSend = ( 6 | from: ProgramClient, 7 | to: ProgramClient, 8 | ms = 3000, 9 | ) => { 10 | const directsub = from.services.pubsub as DirectSub; 11 | for (const [_key, peer] of directsub.peers) { 12 | if (peer.publicKey.equals(to.identity.publicKey)) { 13 | const writeFn = peer.write.bind(peer); 14 | peer.write = async (msg, priority) => { 15 | await delay(ms); 16 | if (peer.outboundStream) { 17 | return writeFn(msg, priority); 18 | } 19 | }; 20 | return; 21 | } 22 | } 23 | throw new Error("Could not find peer"); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/programs/data/document/document/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "checkJs": false, 5 | "strictPropertyInitialization": false, 6 | "experimentalDecorators": true, 7 | "emitDecoratorMetadata": true, 8 | "outDir": "dist" 9 | }, 10 | "include": ["src", "test", "benchmark"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/programs/data/document/interface/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/programs/data/document/interface/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./query.js"; 2 | export * from "./store.js"; 3 | export * from "./request.js"; 4 | -------------------------------------------------------------------------------- /packages/programs/data/document/interface/src/store.ts: -------------------------------------------------------------------------------- 1 | export type IDocumentStore = { 2 | index: { search: (query: any) => Promise }; 3 | }; 4 | -------------------------------------------------------------------------------- /packages/programs/data/document/interface/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | tmp 4 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/README.md: -------------------------------------------------------------------------------- 1 | # Shared log 2 | 3 | A log that can be replicated -------------------------------------------------------------------------------- /packages/programs/data/shared-log/benchmark/memory/utils.ts: -------------------------------------------------------------------------------- 1 | export type Message = 2 | | { type: "init"; storage: "in-memory" | "disc" } 3 | | { type: "insert"; docs: number; size?: number } 4 | | { type: "done" } 5 | | { type: "ready" }; 6 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/src/blocks.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | import { 3 | BlockRequest, 4 | BlockResponse, 5 | BlockMessage as IBlockMessage, 6 | } from "@peerbit/blocks"; 7 | import { TransportMessage } from "./message.js"; 8 | 9 | @variant([2, 0]) 10 | export class BlocksMessage extends TransportMessage { 11 | @field({ type: IBlockMessage }) 12 | message: BlockRequest | BlockResponse; 13 | 14 | constructor(message: BlockRequest | BlockResponse) { 15 | super(); 16 | this.message = message; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/src/debounce.ts: -------------------------------------------------------------------------------- 1 | import { debounceAccumulator } from "@peerbit/time"; 2 | 3 | export const debouncedAccumulatorMap = ( 4 | fn: (args: Map) => any, 5 | delay: number, 6 | merge?: (into: T, from: T) => void, 7 | ) => { 8 | return debounceAccumulator>( 9 | fn, 10 | () => { 11 | const map = new Map(); 12 | let add = merge 13 | ? (props: { key: string; value: T }) => { 14 | let prev = map.get(props.key); 15 | if (prev != null) { 16 | merge(prev, props.value); 17 | } else { 18 | map.set(props.key, props.value); 19 | } 20 | } 21 | : (props: { key: string; value: T }) => { 22 | map.set(props.key, props.value); 23 | }; 24 | return { 25 | add, 26 | delete: (key: string) => map.delete(key), 27 | size: () => map.size, 28 | value: map, 29 | clear: () => map.clear(), 30 | has: (key: string) => map.has(key), 31 | }; 32 | }, 33 | delay, 34 | ); 35 | }; 36 | 37 | export type DebouncedAccumulatorMap = ReturnType< 38 | typeof debouncedAccumulatorMap 39 | >; 40 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/src/errors.ts: -------------------------------------------------------------------------------- 1 | export class NoPeersError extends Error { 2 | constructor(topic: string) { 3 | super( 4 | `No peers found for topic ${topic}. Please make sure you are connected to the network and try again.`, 5 | ); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/src/message.ts: -------------------------------------------------------------------------------- 1 | import { variant } from "@dao-xyz/borsh"; 2 | 3 | @variant(0) 4 | export abstract class TransportMessage {} 5 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/test/append.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestSession } from "@peerbit/test-utils"; 2 | import { expect } from "chai"; 3 | import sinon from "sinon"; 4 | import { EventStore } from "./utils/stores/index.js"; 5 | 6 | describe("append", () => { 7 | let session: TestSession; 8 | 9 | before(async () => {}); 10 | 11 | afterEach(async () => { 12 | await session.stop(); 13 | }); 14 | 15 | it("canAppend checked once", async () => { 16 | session = await TestSession.disconnected(1); 17 | 18 | const store = await session.peers[0].open(new EventStore()); 19 | const canAppend = sinon.spy(store.log.canAppend); 20 | store.log.canAppend = canAppend; 21 | await store.add("a"); 22 | 23 | expect(canAppend.callCount).to.be.eq(1); 24 | }); 25 | 26 | it("override option canAppend checked once", async () => { 27 | session = await TestSession.disconnected(1); 28 | 29 | const store = await session.peers[0].open(new EventStore()); 30 | const canAppend = sinon.spy(store.log.canAppend); 31 | store.log.canAppend = canAppend; 32 | 33 | let canAppendOverride = false; 34 | await store.add("a", { 35 | canAppend: () => { 36 | canAppendOverride = true; 37 | return true; 38 | }, 39 | }); 40 | expect(canAppend.callCount).to.be.eq(1); 41 | expect(canAppendOverride).to.be.true; 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/test/utils/access.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | import { Program } from "@peerbit/program"; 3 | import { EventStore } from "./stores"; 4 | 5 | @variant("test_simple") 6 | export class SimpleStoreContract extends Program { 7 | @field({ type: EventStore }) 8 | store!: EventStore; 9 | 10 | constructor(properties?: { store: EventStore }) { 11 | super(); 12 | if (properties) { 13 | this.store = properties.store; 14 | } 15 | } 16 | open(option?: any): Promise { 17 | return this.store.open(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/test/utils/stores/encoding.ts: -------------------------------------------------------------------------------- 1 | import { type AbstractType, deserialize, serialize } from "@dao-xyz/borsh"; 2 | import { type Encoding } from "@peerbit/log"; 3 | import stringify from "json-stringify-deterministic"; 4 | 5 | const encoder = new TextEncoder(); 6 | const decoder = new TextDecoder(); 7 | 8 | export const JSON_ENCODING: Encoding = { 9 | encoder: (obj: any) => { 10 | return new Uint8Array(encoder.encode(stringify(obj))); 11 | }, 12 | decoder: (bytes: Uint8Array) => { 13 | return JSON.parse(decoder.decode(bytes).toString()); 14 | }, 15 | }; 16 | 17 | export const BORSH_ENCODING = (clazz: AbstractType): Encoding => { 18 | return { 19 | decoder: (bytes: Uint8Array) => deserialize(bytes, clazz), 20 | encoder: (data: any) => serialize(data), 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/test/utils/stores/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./event-store.js"; 2 | -------------------------------------------------------------------------------- /packages/programs/data/shared-log/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "outDir": "dist", 7 | "skipLibCheck": true, 8 | "checkJs": false 9 | }, 10 | "include": ["src", "test", "benchmark"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/programs/data/string/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/programs/data/string/README.md: -------------------------------------------------------------------------------- 1 | # DString 2 | 3 | Distributed string 4 | 5 | This store is built on top of the base store. This store behaves similarly to a git repository, or a collaborative text document. Peers can add and remove content from the string, and read the full string conveniently. 6 | 7 | As of now, go through the tests for documentation. 8 | -------------------------------------------------------------------------------- /packages/programs/data/string/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./string-store.js"; 2 | export * from "./string-index.js"; 3 | export * from "./range.js"; 4 | export * from "./query.js"; 5 | -------------------------------------------------------------------------------- /packages/programs/data/string/src/range.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | 3 | @variant(0) 4 | export class Range { 5 | @field({ type: "u64" }) 6 | offset: bigint; 7 | 8 | @field({ type: "u64" }) 9 | length: bigint; 10 | 11 | constructor(props?: { offset: bigint | number; length: bigint | number }) { 12 | if (props) { 13 | this.offset = 14 | typeof props.offset === "number" ? BigInt(props.offset) : props.offset; 15 | this.length = 16 | typeof props.length === "number" ? BigInt(props.length) : props.length; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/programs/data/string/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/programs/program/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/programs/program/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 dao.xyz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /packages/programs/program/src/address.ts: -------------------------------------------------------------------------------- 1 | export type Address = string; 2 | -------------------------------------------------------------------------------- /packages/programs/program/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | type ProgramInitializationOptions, 3 | type OpenOptions, 4 | } from "./handler.js"; 5 | export * from "./client.js"; 6 | export * from "./program.js"; 7 | export * from "./address.js"; 8 | export type { ExtractArgs } from "./handler.js"; 9 | -------------------------------------------------------------------------------- /packages/programs/program/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type AbstractType, 3 | type Constructor, 4 | getSchemasBottomUp, 5 | } from "@dao-xyz/borsh"; 6 | 7 | export const getValuesWithType = ( 8 | from: any, 9 | type: Constructor | AbstractType, 10 | stopAtType?: Constructor | AbstractType, 11 | ): T[] => { 12 | const schemas = getSchemasBottomUp(from.constructor); 13 | const values: T[] = []; 14 | for (const schema of schemas) { 15 | for (const field of schema.fields) { 16 | const value = from[field.key]; 17 | if (!value) { 18 | continue; 19 | } 20 | const p = (element: any) => { 21 | if (element && element instanceof type) { 22 | values.push(element as T); 23 | } else if (typeof element === "object") { 24 | if (stopAtType && element instanceof stopAtType) { 25 | return; 26 | } 27 | const nestedValues = getValuesWithType(element, type, stopAtType); 28 | nestedValues.forEach((v) => { 29 | values.push(v); 30 | }); 31 | } 32 | }; 33 | if (Array.isArray(value)) { 34 | for (const element of value) { 35 | p(element); 36 | } 37 | } else { 38 | p(value); 39 | } 40 | } 41 | } 42 | return values; 43 | }; 44 | -------------------------------------------------------------------------------- /packages/programs/program/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"], 10 | "exclude": ["node_modules", "dist"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/programs/rpc/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/programs/rpc/documentation/rpc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/packages/programs/rpc/documentation/rpc1.png -------------------------------------------------------------------------------- /packages/programs/rpc/documentation/rpc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dao-xyz/peerbit/37af264b5d4f74ed4c304b823fce10c4469b2844/packages/programs/rpc/documentation/rpc2.png -------------------------------------------------------------------------------- /packages/programs/rpc/src/encoding.ts: -------------------------------------------------------------------------------- 1 | import { field, fixedArray, option, variant } from "@dao-xyz/borsh"; 2 | import { MaybeEncrypted, X25519PublicKey } from "@peerbit/crypto"; 3 | 4 | @variant(0) 5 | export abstract class RPCMessage {} 6 | 7 | @variant(0) 8 | export class RequestV0 extends RPCMessage { 9 | @field({ type: option(X25519PublicKey) }) 10 | respondTo?: X25519PublicKey; 11 | 12 | @field({ type: MaybeEncrypted }) 13 | request: MaybeEncrypted; 14 | 15 | constructor(properties: { 16 | request: MaybeEncrypted; 17 | respondTo?: X25519PublicKey; 18 | }) { 19 | super(); 20 | this.respondTo = properties.respondTo; 21 | this.request = properties.request; 22 | } 23 | } 24 | 25 | @variant(1) 26 | export class ResponseV0 extends RPCMessage { 27 | @field({ type: fixedArray("u8", 32) }) 28 | requestId: Uint8Array; 29 | 30 | @field({ type: MaybeEncrypted }) 31 | response: MaybeEncrypted; 32 | 33 | constructor(properties: { 34 | response: MaybeEncrypted; 35 | requestId: Uint8Array; 36 | }) { 37 | super(); 38 | this.response = properties.response; 39 | this.requestId = properties.requestId; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/programs/rpc/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./encoding.js"; 2 | export * from "./io.js"; 3 | export * from "./controller.js"; 4 | export * from "./utils.js"; 5 | -------------------------------------------------------------------------------- /packages/programs/rpc/src/io.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Ed25519PublicKey, 3 | PublicSignKey, 4 | X25519Keypair, 5 | X25519PublicKey, 6 | } from "@peerbit/crypto"; 7 | import { logger as loggerFn } from "@peerbit/logger"; 8 | import type { 9 | DataMessage, 10 | PriorityOptions, 11 | WithExtraSigners, 12 | WithMode, 13 | } from "@peerbit/stream-interface"; 14 | 15 | export const logger = loggerFn({ module: "rpc" }); 16 | export type RPCRequestResponseOptions = { 17 | amount?: number; 18 | timeout?: number; 19 | isTrusted?: (publicKey: PublicSignKey) => Promise; 20 | onResponse?: (response: R, from?: PublicSignKey) => void; 21 | signal?: AbortSignal; 22 | }; 23 | 24 | export type RequestResponseInterceptor = { 25 | responseInterceptor?: (fn: (response: RPCResponse) => void) => void; 26 | }; 27 | 28 | export type RPCRequestOptions = RPCRequestResponseOptions & 29 | EncryptionOptions & 30 | WithMode & 31 | PriorityOptions & 32 | WithExtraSigners & 33 | RequestResponseInterceptor; 34 | 35 | export type EncryptionOptions = { 36 | encryption?: { 37 | key: X25519Keypair; 38 | responders?: (X25519PublicKey | Ed25519PublicKey)[]; 39 | }; 40 | }; 41 | 42 | export type RPCResponse = { 43 | response: R; 44 | message: DataMessage; 45 | from?: PublicSignKey; 46 | }; 47 | -------------------------------------------------------------------------------- /packages/programs/rpc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/transport/blocks-interface/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .nyc_output 3 | coverage 4 | -------------------------------------------------------------------------------- /packages/transport/blocks-interface/README.md: -------------------------------------------------------------------------------- 1 | # Direct block interface 2 | 3 | Message types for the Block swap/share protocol 4 | -------------------------------------------------------------------------------- /packages/transport/blocks-interface/src/index.ts: -------------------------------------------------------------------------------- 1 | import { type WaitForPeer } from "@peerbit/stream-interface"; 2 | import { type Block } from "multiformats/block"; 3 | 4 | export type GetOptions = { 5 | remote?: 6 | | { 7 | signal?: AbortSignal; 8 | timeout?: number; 9 | replicate?: boolean; 10 | from?: string[]; 11 | } 12 | | boolean; 13 | }; 14 | export type PutOptions = { 15 | timeout?: number; 16 | }; 17 | 18 | type MaybePromise = Promise | T; 19 | 20 | export interface Blocks extends WaitForPeer { 21 | put( 22 | data: Uint8Array | { block: Block; cid: string }, 23 | ): MaybePromise; 24 | has(cid: string): MaybePromise; 25 | get(cid: string, options?: GetOptions): MaybePromise; 26 | rm(cid: string): MaybePromise; 27 | iterator(): AsyncGenerator<[string, Uint8Array], void, void>; 28 | size(): MaybePromise; 29 | persisted(): MaybePromise; 30 | } 31 | 32 | export { 33 | cidifyString, 34 | stringifyCid, 35 | createBlock, 36 | getBlockValue, 37 | calculateRawCid, 38 | checkDecodeBlock, 39 | codecCodes, 40 | defaultHasher, 41 | codecMap, 42 | } from "./block.js"; 43 | -------------------------------------------------------------------------------- /packages/transport/blocks-interface/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/transport/blocks/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .nyc_output 3 | coverage 4 | -------------------------------------------------------------------------------- /packages/transport/blocks/README.md: -------------------------------------------------------------------------------- 1 | # Direct block 2 | 3 | Block swap/share protocol built on top of [Direct Stream](./../direct-stream/README.md) 4 | -------------------------------------------------------------------------------- /packages/transport/blocks/src/index.ts: -------------------------------------------------------------------------------- 1 | export { DirectBlock } from "./libp2p.js"; 2 | export * from "./interface.js"; 3 | export * from "./any-blockstore.js"; 4 | export * from "./libp2p.js"; 5 | export * from "./remote.js"; 6 | -------------------------------------------------------------------------------- /packages/transport/blocks/src/interface.ts: -------------------------------------------------------------------------------- 1 | import type { MaybePromise } from "@peerbit/any-store-interface"; 2 | import type { Blocks as IBlockStore } from "@peerbit/blocks-interface"; 3 | 4 | export type StoreStatus = MaybePromise< 5 | "open" | "opening" | "closed" | "closing" 6 | >; 7 | export interface BlockStore extends IBlockStore { 8 | start(): Promise; 9 | stop(): Promise; 10 | status(): StoreStatus; 11 | } 12 | -------------------------------------------------------------------------------- /packages/transport/blocks/test/level.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { equals } from "uint8arrays"; 3 | import { AnyBlockStore } from "../src/any-blockstore.js"; 4 | 5 | describe(`level`, function () { 6 | let store: AnyBlockStore; 7 | 8 | afterEach(async () => { 9 | await store.stop(); 10 | }); 11 | 12 | it("rw", async () => { 13 | store = new AnyBlockStore(); 14 | await store.start(); 15 | const data = new Uint8Array([1, 2, 3]); 16 | const cid = await store.put(data); 17 | expect(cid).equal("zb2rhWtC5SY6zV1y2SVN119ofpxsbEtpwiqSoK77bWVzHqeWU"); 18 | 19 | const readData = await store.get(cid); 20 | expect(readData).to.deep.equal(data); 21 | }); 22 | 23 | it("iterate", async () => { 24 | store = new AnyBlockStore(); 25 | await store.start(); 26 | let datas = [new Uint8Array([0]), new Uint8Array([1])]; 27 | const cids = await Promise.all(datas.map((x) => store.put(x))); 28 | let allKeys = new Set(); 29 | for await (const [key, value] of store.iterator()) { 30 | let found = false; 31 | for (let i = 0; i < cids.length; i++) { 32 | if (key === cids[i] && equals(new Uint8Array(value), datas[i])) { 33 | found = true; 34 | } 35 | } 36 | 37 | expect(found).to.be.true; 38 | 39 | allKeys.add(key); 40 | } 41 | 42 | expect(allKeys.size).equal(2); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /packages/transport/blocks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test", "benchmark"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/transport/libp2p-test-utils/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .nyc_output 3 | coverage 4 | -------------------------------------------------------------------------------- /packages/transport/libp2p-test-utils/src/index.ts: -------------------------------------------------------------------------------- 1 | import { TestSession } from "./session.js"; 2 | 3 | export { TestSession }; 4 | -------------------------------------------------------------------------------- /packages/transport/libp2p-test-utils/src/transports.ts: -------------------------------------------------------------------------------- 1 | import { 2 | circuitRelayServer, 3 | circuitRelayTransport, 4 | } from "@libp2p/circuit-relay-v2"; 5 | import type { Transport } from "@libp2p/interface"; 6 | import { webRTC } from "@libp2p/webrtc"; 7 | import { webSockets } from "@libp2p/websockets"; 8 | import * as filters from "@libp2p/websockets/filters"; 9 | import type { Components } from "libp2p/components"; 10 | 11 | export const transports = (): Array<(components: Components) => Transport> => [ 12 | circuitRelayTransport({ 13 | reservationCompletionTimeout: 5000, 14 | }), 15 | webRTC({}), 16 | webSockets({ filter: filters.all }), 17 | ]; 18 | 19 | // applyDefaultLimit: false because of https://github.com/libp2p/js-libp2p/issues/2622 20 | export const relay = () => 21 | circuitRelayServer({ reservations: { applyDefaultLimit: false } }); 22 | 23 | export const listen = () => [ 24 | "/ip4/127.0.0.1/tcp/0", 25 | "/ip4/127.0.0.1/tcp/0/ws", 26 | "/p2p-circuit", 27 | ]; 28 | -------------------------------------------------------------------------------- /packages/transport/libp2p-test-utils/test/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestSession } from "../src/session.js"; 2 | 3 | it("connect", async () => { 4 | const session = await TestSession.connected(3); 5 | await session.stop(); 6 | }); 7 | -------------------------------------------------------------------------------- /packages/transport/libp2p-test-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/transport/pubsub-interface/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .nyc_output 3 | coverage 4 | -------------------------------------------------------------------------------- /packages/transport/pubsub-interface/README.md: -------------------------------------------------------------------------------- 1 | # Pubsub interface 2 | 3 | Message specifications for the PubSub protocol 4 | -------------------------------------------------------------------------------- /packages/transport/pubsub-interface/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "outDir": "dist" 7 | }, 8 | "include": ["src", "test"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/transport/pubsub/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .nyc_output 3 | coverage 4 | -------------------------------------------------------------------------------- /packages/transport/pubsub/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test", "benchmark"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/transport/stream-interface/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .nyc_output 3 | coverage 4 | -------------------------------------------------------------------------------- /packages/transport/stream-interface/README.md: -------------------------------------------------------------------------------- 1 | # Stream interface 2 | 3 | Message types for the Stream protocol 4 | -------------------------------------------------------------------------------- /packages/transport/stream-interface/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { PeerId } from "@libp2p/interface"; 2 | import type { PublicSignKey } from "@peerbit/crypto"; 3 | import type { DataMessage, Message } from "./messages.js"; 4 | 5 | export interface PeerEvents { 6 | "peer:session": CustomEvent; 7 | "peer:reachable": CustomEvent; 8 | "peer:unreachable": CustomEvent; 9 | } 10 | 11 | export interface MessageEvents { 12 | message: CustomEvent; 13 | } 14 | export interface StreamEvents extends PeerEvents, MessageEvents { 15 | data: CustomEvent; 16 | } 17 | 18 | export * from "./messages.js"; 19 | 20 | export interface WaitForPeer { 21 | waitFor( 22 | peer: PeerId | PublicSignKey | string, 23 | options?: { signal?: AbortSignal }, 24 | ): Promise; 25 | } 26 | 27 | export interface PublicKeyFromHashResolver { 28 | getPublicKey( 29 | hash: string, 30 | ): PublicSignKey | undefined | Promise; 31 | } 32 | 33 | export class NotStartedError extends Error { 34 | constructor() { 35 | super("Not started"); 36 | } 37 | } 38 | 39 | export class DeliveryError extends Error {} 40 | export class InvalidMessageError extends Error {} 41 | -------------------------------------------------------------------------------- /packages/transport/stream-interface/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/transport/stream/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .nyc_output 3 | coverage 4 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | dist 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | /test-results/ 27 | /playwright-report/ 28 | /playwright/.cache/ 29 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/browser-node/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | dist 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/browser-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stream-browser-test-vite", 3 | "private": true, 4 | "version": "0.2.2", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "start": "vite", 9 | "build": "tsc && vite build", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "@peerbit/stream": "*", 16 | "libp2p": "^2.8.9" 17 | }, 18 | "devDependencies": { 19 | "@types/react": "^18.2.12", 20 | "@types/react-dom": "^18.2.5", 21 | "@vitejs/plugin-react": "^4.2.1", 22 | "vite": "^6.0.6" 23 | }, 24 | "browserslist": { 25 | "production": [ 26 | "chrome >= 67", 27 | "edge >= 79", 28 | "firefox >= 68", 29 | "opera >= 54", 30 | "safari >= 14" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/browser-node/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Peerbit node", 3 | "name": "Peerbit node", 4 | "icons": [], 5 | "start_url": ".", 6 | "display": "standalone", 7 | "theme_color": "#000000", 8 | "background_color": "#ffffff" 9 | } 10 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/browser-node/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/browser-node/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/browser-node/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { App } from "./App"; 4 | import "./index.css"; 5 | 6 | const root = ReactDOM.createRoot( 7 | document.getElementById("root") as HTMLElement, 8 | ); 9 | root.render( 10 | 11 | 12 | , 13 | ); 14 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/browser-node/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/browser-node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "Es2022"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "es2022", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "experimentalDecorators": true, 17 | "noEmit": true, 18 | "jsx": "react-jsx" 19 | }, 20 | "include": ["src"], 21 | "references": [ 22 | { 23 | "path": "./tsconfig.node.json" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/browser-node/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "es2022", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/browser-node/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from "@vitejs/plugin-react"; 2 | import { defineConfig } from "vite"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | optimizeDeps: { 8 | esbuildOptions: { 9 | target: "esnext", 10 | }, 11 | }, 12 | build: { 13 | target: "esnext", 14 | }, 15 | server: { 16 | port: 5211, 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stream-browser-test", 3 | "private": true, 4 | "version": "0.2.2", 5 | "type": "module", 6 | "browserslist": { 7 | "production": [ 8 | "chrome >= 67", 9 | "edge >= 79", 10 | "firefox >= 68", 11 | "opera >= 54", 12 | "safari >= 14" 13 | ], 14 | "development": [ 15 | "last 1 chrome version", 16 | "last 1 firefox version", 17 | "last 1 safari version" 18 | ] 19 | }, 20 | "scripts": { 21 | "test": "playwright test", 22 | "lint": "aegir lint" 23 | }, 24 | "dependencies": { 25 | "@peerbit/stream": "*" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/shared/bin.ts: -------------------------------------------------------------------------------- 1 | import { noise } from "@chainsafe/libp2p-noise"; 2 | import { yamux } from "@chainsafe/libp2p-yamux"; 3 | import { circuitRelayServer } from "@libp2p/circuit-relay-v2"; 4 | import { identify } from "@libp2p/identify"; 5 | import { webSockets } from "@libp2p/websockets"; 6 | import { all } from "@libp2p/websockets/filters"; 7 | import { createLibp2p } from "libp2p"; 8 | import { TestDirectStream } from "./utils.js"; 9 | 10 | // Run with "node --loader ts-node/esm ./test/browser/shared/bin.ts" 11 | const relay = await createLibp2p<{ 12 | relay: any; 13 | identify: any; 14 | stream: TestDirectStream; 15 | }>({ 16 | addresses: { 17 | listen: ["/ip4/127.0.0.1/tcp/0/ws"], 18 | }, 19 | services: { 20 | // applyDefaultLimit: false because of https://github.com/libp2p/js-libp2p/issues/2622 21 | relay: circuitRelayServer({ 22 | reservations: { applyDefaultLimit: false, maxReservations: 1000 }, 23 | }), 24 | identify: identify(), 25 | stream: (c) => new TestDirectStream(c), 26 | }, 27 | transports: [webSockets({ filter: all })], 28 | streamMuxers: [yamux()], 29 | connectionEncrypters: [noise()], 30 | }); 31 | console.log(relay.getMultiaddrs().map((x) => x.toString())); 32 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/shared/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type ConnectionManagerArguments, 3 | DirectStream, 4 | type DirectStreamComponents, 5 | } from "@peerbit/stream"; 6 | 7 | export class TestDirectStream extends DirectStream { 8 | constructor( 9 | components: DirectStreamComponents, 10 | options: { 11 | id?: string; 12 | connectionManager?: ConnectionManagerArguments; 13 | } = {}, 14 | ) { 15 | super(components, [options.id || "/browser-test/0.0.0"], { 16 | canRelayMessage: true, 17 | connectionManager: options.connectionManager || false, 18 | ...options, 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/transport/stream/e2e/browser/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["shared", "tests"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/transport/stream/src/logger.ts: -------------------------------------------------------------------------------- 1 | import { logger as logFn } from "@peerbit/logger"; 2 | 3 | export const logger = logFn({ module: "lazystream", level: "warn" }); 4 | -------------------------------------------------------------------------------- /packages/transport/stream/src/stats.ts: -------------------------------------------------------------------------------- 1 | import { MovingAverageTracker } from "@peerbit/time"; 2 | 3 | export class BandwidthTracker { 4 | private ma: MovingAverageTracker; 5 | private interval: ReturnType; 6 | constructor(tau = 0.2) { 7 | this.ma = new MovingAverageTracker(tau); 8 | } 9 | start() { 10 | // Add 0 every second to make the tracker go to 0 over time 11 | this.interval = setInterval(() => { 12 | this.ma.add(0); 13 | }, 1000); 14 | } 15 | get value() { 16 | return this.ma.value; 17 | } 18 | add(number: number) { 19 | this.ma.add(number); 20 | } 21 | stop() { 22 | clearInterval(this.interval); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/transport/stream/test/stats.spec.ts: -------------------------------------------------------------------------------- 1 | import { delay } from "@peerbit/time"; 2 | import { expect } from "chai"; 3 | import { BandwidthTracker } from "../src/stats.js"; 4 | 5 | describe("bandwidth-tracker", () => { 6 | let tracker: BandwidthTracker; 7 | beforeEach(() => { 8 | tracker = new BandwidthTracker(); 9 | tracker.start(); 10 | }); 11 | afterEach(() => { 12 | tracker.stop(); 13 | }); 14 | it("resets after a while", async () => { 15 | expect(tracker.value).equal(0); 16 | tracker.add(1e3); 17 | let v0 = tracker.value; 18 | expect(v0).greaterThan(0); 19 | await delay(1000); 20 | const v1 = tracker.value; 21 | expect(v1).lessThan(v0); 22 | expect(v1).greaterThan(5); 23 | await delay(2000); 24 | const v2 = tracker.value; 25 | expect(v2).lessThan(1); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /packages/transport/stream/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test", "benchmark"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/any-store/any-store/.aegir.js: -------------------------------------------------------------------------------- 1 | import findUp from "find-up"; 2 | import path from "path"; 3 | 4 | const root = path.dirname(findUp.sync(".git", { type: "directory" })); 5 | 6 | export default { 7 | test: { 8 | build: true, 9 | runner: "node", 10 | target: ["node", "browser", "webworker"], 11 | watch: false, 12 | files: [], 13 | timeout: 60000, 14 | 15 | grep: "", 16 | bail: false, 17 | debug: true, 18 | progress: false, 19 | cov: false, 20 | covTimeout: 60000, 21 | browser: { 22 | config: { 23 | assets: "../../../../node_modules/@peerbit/any-store-opfs/dist", 24 | buildConfig: { 25 | conditions: ["production"], 26 | }, 27 | }, 28 | }, 29 | before: () => { 30 | return { 31 | env: { TS_NODE_PROJECT: path.join(root, "tsconfig.test.json") }, 32 | }; 33 | }, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /packages/utils/any-store/any-store/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | lib -------------------------------------------------------------------------------- /packages/utils/any-store/any-store/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { AnyStore } from "@peerbit/any-store-interface"; 2 | 3 | export { createStore } from "./store.js"; 4 | 5 | export type { AnyStore }; 6 | -------------------------------------------------------------------------------- /packages/utils/any-store/any-store/src/store.browser.ts: -------------------------------------------------------------------------------- 1 | import { OPFSStore } from "@peerbit/any-store-opfs/opfs-store"; 2 | import { MemoryStore } from "./memory.js"; 3 | 4 | export const createStore = (directory?: string) => { 5 | return directory ? new OPFSStore(directory) : new MemoryStore(); 6 | }; 7 | 8 | /* export const estimate = (directory: string): Promise<{ quota?: number, usage?: number }> => { 9 | return navigator.storage.estimate().then(x => { return { quota: x.quota, usage: x.usage } }) 10 | } */ 11 | -------------------------------------------------------------------------------- /packages/utils/any-store/any-store/src/store.ts: -------------------------------------------------------------------------------- 1 | import { Level } from "level"; 2 | import { LevelStore } from "./level.js"; 3 | import { MemoryStore } from "./memory.js"; 4 | 5 | /* import os from 'os' 6 | import { check } from 'diskusage' */ 7 | 8 | export const createStore = (directory?: string) => { 9 | return directory 10 | ? new LevelStore(new Level(directory, { valueEncoding: "view" }) as any) // TODO types? hooks does not seem to be updated 11 | : new MemoryStore(); 12 | }; 13 | 14 | /* export const estimate = (directory: string): Promise<{ quota?: number, usage?: number }> => { 15 | return check(directory).then(x => { return { quota: x.total, usage: x.total - x.free } }) 16 | } */ 17 | -------------------------------------------------------------------------------- /packages/utils/any-store/any-store/src/worker-import.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*?worker&url" { 2 | const url: string; 3 | export default url; 4 | } 5 | -------------------------------------------------------------------------------- /packages/utils/any-store/any-store/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/any-store/interface/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | lib -------------------------------------------------------------------------------- /packages/utils/any-store/interface/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.0 (2024-07-20) 4 | 5 | 6 | ### Features 7 | 8 | * add api for determining if persistant ([bc9e218](https://github.com/dao-xyz/peerbit/commit/bc9e218651a086ded8e7eaebaf15f3ce0db176d0)) 9 | 10 | 11 | ### Bug Fixes 12 | 13 | * fmt ([bdee4f4](https://github.com/dao-xyz/peerbit/commit/bdee4f4943fcabd21c53a4f37dba17d04cea2577)) 14 | * peerbit eslint rules ([5056694](https://github.com/dao-xyz/peerbit/commit/5056694f90ad03c0c5ba1e47c6ac57387d85aba9)) 15 | * remove invalid change logs ([a9206a8](https://github.com/dao-xyz/peerbit/commit/a9206a802e97e08caf8f187e2b033046bab0ba7c)) 16 | -------------------------------------------------------------------------------- /packages/utils/any-store/interface/src/index.ts: -------------------------------------------------------------------------------- 1 | export type MaybePromise = Promise | T; 2 | 3 | export interface AnyStore { 4 | status(): MaybePromise<"opening" | "open" | "closing" | "closed">; 5 | close(): MaybePromise; 6 | open(): MaybePromise; 7 | get(key: string): MaybePromise; 8 | put(key: string, value: Uint8Array): MaybePromise; 9 | del(key: string): MaybePromise; 10 | sublevel(name: string): MaybePromise; 11 | iterator: () => { 12 | [Symbol.asyncIterator]: () => AsyncIterator< 13 | [string, Uint8Array], 14 | void, 15 | void 16 | >; 17 | }; 18 | clear(): MaybePromise; 19 | size(): MaybePromise; 20 | persisted(): MaybePromise; 21 | } 22 | -------------------------------------------------------------------------------- /packages/utils/any-store/interface/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/any-store/opfs/.aegir.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // global options 3 | debug: false, 4 | // test cmd options 5 | build: { 6 | bundle: true, 7 | bundlesize: false, 8 | bundlesizeMax: "100kB", 9 | types: true, 10 | config: { 11 | minify: true, 12 | outfile: "dist/peerbit/anystore-opfs-worker.min.js", 13 | banner: { js: "" }, 14 | footer: { js: "" }, 15 | }, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/utils/any-store/opfs/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | lib -------------------------------------------------------------------------------- /packages/utils/any-store/opfs/src/create.ts: -------------------------------------------------------------------------------- 1 | const createWorker = (directory: string) => { 2 | const worker = new Worker( 3 | new URL( 4 | "/peerbit/anystore-opfs-worker.min.js#" + directory, 5 | import.meta.url, 6 | ), 7 | { type: "classic" }, 8 | ); 9 | return worker; 10 | }; 11 | export { createWorker }; 12 | -------------------------------------------------------------------------------- /packages/utils/any-store/opfs/src/index.ts: -------------------------------------------------------------------------------- 1 | import "./worker.js"; 2 | -------------------------------------------------------------------------------- /packages/utils/any-store/opfs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/cache/.gitignore: -------------------------------------------------------------------------------- 1 | dump.rdb 2 | orbitdb.json 3 | node_modules 4 | redis-stable* 5 | test/browser/bundle.js* 6 | -------------------------------------------------------------------------------- /packages/utils/cache/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2018 Protocol Labs Inc. 4 | Copyright (c) 2018 Haja Networks Oy 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /packages/utils/cache/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/crypto/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/utils/crypto/README.md: -------------------------------------------------------------------------------- 1 | # crypto primitives 2 | 3 | Crypto primitives -------------------------------------------------------------------------------- /packages/utils/crypto/benchmark/peer-ids.ts: -------------------------------------------------------------------------------- 1 | import { deserialize, serialize } from "@dao-xyz/borsh"; 2 | import { generateKeyPair } from "@libp2p/crypto/keys"; 3 | import { peerIdFromPublicKey } from "@libp2p/peer-id"; 4 | import B from "benchmark"; 5 | import { Ed25519Keypair, Ed25519PublicKey } from "../src/ed25519.js"; 6 | 7 | //node --loader ts-node/esm ./benchmark/peer-ids.ts 8 | 9 | const keypair = await Ed25519Keypair.create(); 10 | const peerId = await generateKeyPair("Ed25519"); 11 | const peerIdPublicKey = peerIdFromPublicKey(peerId.publicKey); 12 | const suite = new B.Suite("ed25519"); 13 | 14 | // TODO this benchmark makes no sense to do anymore since libp2p 2.0.0. What we want to compare is the ser/der perform of libp2p peerid vs peerbit peerid 15 | suite 16 | .add("PublicSignKey", { 17 | fn: async () => { 18 | deserialize(serialize(keypair.publicKey), Ed25519PublicKey); 19 | }, 20 | }) 21 | .add("PeerId ", { 22 | fn: () => { 23 | peerIdFromPublicKey(peerIdPublicKey.publicKey); 24 | }, 25 | }) 26 | .on("error", (error: any) => { 27 | throw error; 28 | }) 29 | .on("cycle", (event: any) => { 30 | console.log(String(event.target)); 31 | }) 32 | .run(); 33 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/bytes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {ArrayBufferView|ArrayBuffer|Uint8Array} o 3 | * @returns {Uint8Array} 4 | */ 5 | export const coerce = (o: any) => { 6 | if (o instanceof Uint8Array && o.constructor.name === "Uint8Array") return o; 7 | if (o instanceof ArrayBuffer) return new Uint8Array(o); 8 | if (ArrayBuffer.isView(o)) { 9 | return new Uint8Array(o.buffer, o.byteOffset, o.byteLength); 10 | } 11 | throw new Error("Unknown type, must be binary type"); 12 | }; 13 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/ed25519-sign.browser.ts: -------------------------------------------------------------------------------- 1 | import sodium from "libsodium-wrappers"; 2 | import type { Ed25519Keypair, Ed25519PublicKey } from "./ed25519.js"; 3 | import { type PreHash, prehashFn } from "./prehash.js"; 4 | import { SignatureWithKey } from "./signature.js"; 5 | 6 | export const sign = async ( 7 | data: Uint8Array, 8 | keypair: Ed25519Keypair, 9 | prehash: PreHash, 10 | ) => { 11 | const hashedData = await prehashFn(data, prehash); 12 | /* const init = sodium.crypto_sign_init() 13 | sodium.crypto_sign_update(init, hashedData) 14 | const signature = sodium.crypto_sign_final_create(init, keypair.privateKey.privateKey, 'uint8array') */ 15 | return new SignatureWithKey({ 16 | prehash, 17 | publicKey: keypair.publicKey, 18 | signature: sodium.crypto_sign_detached( 19 | hashedData, 20 | keypair.privateKeyPublicKey, 21 | ), 22 | }); 23 | }; 24 | 25 | export const verifySignatureEd25519 = async ( 26 | signature: SignatureWithKey, 27 | data: Uint8Array, 28 | ) => { 29 | let res = false; 30 | try { 31 | const hashedData = await prehashFn(data, signature.prehash); 32 | 33 | const verified = sodium.crypto_sign_verify_detached( 34 | signature.signature, 35 | hashedData, 36 | (signature.publicKey as Ed25519PublicKey).publicKey, 37 | ); 38 | res = verified; 39 | } catch (error) { 40 | return false; 41 | } 42 | return res; 43 | }; 44 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/errors.ts: -------------------------------------------------------------------------------- 1 | export class AccessError extends Error { 2 | constructor(message: string = "Access denied") { 3 | super(message); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/hash.browser.ts: -------------------------------------------------------------------------------- 1 | import { SHA256 } from "@stablelib/sha256"; 2 | import { toBase64 } from "./utils.js"; 3 | 4 | export const sha256Base64 = async (bytes: Uint8Array): Promise => 5 | toBase64(await sha256(bytes)); 6 | export const sha256Base64Sync = (bytes: Uint8Array): string => 7 | toBase64(new SHA256().update(bytes).digest()); 8 | export const sha256 = async (bytes: Uint8Array): Promise => 9 | new Uint8Array(await globalThis.crypto.subtle.digest("SHA-256", bytes)); 10 | export const sha256Sync = (bytes: Uint8Array): Uint8Array => 11 | new SHA256().update(bytes).digest(); 12 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/hash.ts: -------------------------------------------------------------------------------- 1 | import crypto from "crypto"; 2 | 3 | export const sha256Base64Sync = (bytes: Uint8Array): string => 4 | crypto.createHash("sha256").update(bytes).digest("base64"); 5 | export const sha256Base64 = async (bytes: Uint8Array): Promise => 6 | crypto.createHash("sha256").update(bytes).digest("base64"); 7 | export const sha256 = async (bytes: Uint8Array): Promise => 8 | crypto.createHash("sha256").update(bytes).digest(); 9 | export const sha256Sync = (bytes: Uint8Array): Uint8Array => 10 | crypto.createHash("sha256").update(bytes).digest(); 11 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/index.ts: -------------------------------------------------------------------------------- 1 | import libsodium from "libsodium-wrappers"; 2 | 3 | export * from "./key.js"; 4 | export * from "./ed25519.js"; 5 | export * from "./signature.js"; 6 | export * from "./sepc256k1.js"; 7 | export * from "./x25519.js"; 8 | export * from "./encryption.js"; 9 | export * from "./from.js"; 10 | export * from "./utils.js"; 11 | export * from "./hash.js"; 12 | export * from "./random.js"; 13 | export * from "./prehash.js"; 14 | export * from "./signer.js"; 15 | export * from "./from.js"; 16 | 17 | const ready = libsodium.ready; 18 | export { ready }; 19 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/prehash.ts: -------------------------------------------------------------------------------- 1 | import { toUtf8Bytes } from "@ethersproject/strings"; 2 | import sha3 from "js-sha3"; 3 | import { concat } from "uint8arrays"; 4 | import { sha256 } from "./hash.js"; 5 | 6 | const messagePrefix = "\x19Ethereum Signed Message:\n"; 7 | const ethKeccak256Hash = (message: Uint8Array) => 8 | new Uint8Array( 9 | sha3.keccak256 10 | .update( 11 | concat([ 12 | toUtf8Bytes(messagePrefix), 13 | toUtf8Bytes(String(message.length)), 14 | message, 15 | ]), 16 | ) 17 | .arrayBuffer(), 18 | ); 19 | 20 | export enum PreHash { 21 | NONE = 0, 22 | SHA_256 = 1, 23 | // BLAKE3 = 2, 24 | ETH_KECCAK_256 = 3, 25 | } 26 | 27 | export const prehashFn = ( 28 | data: Uint8Array, 29 | prehash: PreHash, 30 | ): Promise | Uint8Array => { 31 | if (prehash === PreHash.NONE) { 32 | return data; 33 | } 34 | if (prehash === PreHash.SHA_256) { 35 | return sha256(data); 36 | } 37 | if (prehash === PreHash.ETH_KECCAK_256) { 38 | return ethKeccak256Hash(data); 39 | } 40 | 41 | throw new Error("Unsupported"); 42 | }; 43 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/random.browser.ts: -------------------------------------------------------------------------------- 1 | export const randomBytes = (len: number) => 2 | globalThis.crypto.getRandomValues(new Uint8Array(len)); 3 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/random.ts: -------------------------------------------------------------------------------- 1 | import crypto from "crypto"; 2 | 3 | export const randomBytes = (len: number) => crypto.randomBytes(len); 4 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/signer.ts: -------------------------------------------------------------------------------- 1 | import type { PublicSignKey } from "./key.js"; 2 | import type { PreHash } from "./prehash.js"; 3 | import type { SignatureWithKey } from "./signature.js"; 4 | 5 | export interface Signer { 6 | sign: ( 7 | bytes: Uint8Array, 8 | prehash?: PreHash, 9 | ) => Promise | SignatureWithKey; 10 | } 11 | 12 | export type SignWithKey = ( 13 | bytes: Uint8Array, 14 | ) => Promise | SignatureWithKey; 15 | 16 | export type Identity = Signer & { 17 | publicKey: T; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/utils/crypto/src/utils.ts: -------------------------------------------------------------------------------- 1 | import sodium from "libsodium-wrappers"; 2 | import { base58btc } from "multiformats/bases/base58"; 3 | 4 | export const fromHexString = (hexString: string) => sodium.from_hex(hexString); 5 | 6 | export const toHexString = (bytes: Uint8Array) => sodium.to_hex(bytes); 7 | 8 | export const toBase64 = (arr: Uint8Array) => { 9 | return sodium.to_base64(arr, sodium.base64_variants.ORIGINAL); 10 | }; 11 | export const fromBase64 = (base64: string) => { 12 | return sodium.from_base64(base64, sodium.base64_variants.ORIGINAL); 13 | }; 14 | 15 | export const toBase64URL = (arr: Uint8Array) => { 16 | return sodium.to_base64(arr, sodium.base64_variants.URLSAFE); 17 | }; 18 | export const fromBase64URL = (base64: string) => { 19 | return sodium.from_base64(base64, sodium.base64_variants.URLSAFE); 20 | }; 21 | 22 | export const toBase58 = (arr: Uint8Array) => { 23 | return base58btc.baseEncode(arr); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/utils/crypto/test/hash.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import sodium from "libsodium-wrappers"; 3 | import { equals } from "uint8arrays"; 4 | import { 5 | sha256, 6 | sha256Base64, 7 | sha256Base64 as sha256Base64Browser, 8 | sha256Base64Sync, 9 | sha256Base64Sync as sha256Base64SyncBrowser, 10 | sha256 as sha256Browser, 11 | sha256Sync, 12 | sha256Sync as sha256SyncBrowser, 13 | } from "../src/hash.js"; 14 | 15 | describe("hash", () => { 16 | before(async () => { 17 | await sodium.ready; 18 | }); 19 | it("sha256", async () => { 20 | const data = new Uint8Array([1, 2, 3]); 21 | expect(equals(await sha256(data), await sha256Browser(data))).to.be.true; 22 | }); 23 | 24 | it("sha256Sync", async () => { 25 | const data = new Uint8Array([1, 2, 3]); 26 | expect(equals(sha256Sync(data), sha256SyncBrowser(data))).to.be.true; 27 | }); 28 | 29 | it("sha256Base64", async () => { 30 | const data = new Uint8Array([1, 2, 3]); 31 | expect(await sha256Base64(data)).equal(await sha256Base64Browser(data)); 32 | }); 33 | 34 | it("sha256Base64Sync", async () => { 35 | const data = new Uint8Array([1, 2, 3]); 36 | expect(sha256Base64Sync(data)).equal(sha256Base64SyncBrowser(data)); 37 | expect(sha256Base64Sync(data)).equal(await sha256Base64Browser(data)); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /packages/utils/crypto/test/random.spec.ts: -------------------------------------------------------------------------------- 1 | /* import { webcrypto } from "crypto"; */ 2 | import { expect } from "chai"; 3 | import { randomBytes } from "../src/random.js"; 4 | 5 | /* globalThis.crypto = webcrypto as any; */ 6 | 7 | const testRandom = (bytes: Uint8Array) => { 8 | const set = new Set(); 9 | for (const byte of bytes) { 10 | set.add(byte); 11 | } 12 | // check some randomness 13 | if (set.size === 1) { 14 | throw new Error(); 15 | } 16 | }; 17 | it("randomBytes", async () => { 18 | const bytes = randomBytes(32); 19 | testRandom(bytes); 20 | expect(bytes).to.have.length(32); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/utils/crypto/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | // allow top level await 5 | "experimentalDecorators": true, 6 | "emitDecoratorMetadata": true, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test", "benchmark"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/indexer/cached-index/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/utils/indexer/cached-index/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "outDir": "dist", 7 | "strictFunctionTypes": true 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/indexer/interface/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/utils/indexer/interface/src/errors.ts: -------------------------------------------------------------------------------- 1 | export class NotStartedError extends Error { 2 | constructor() { 3 | super("Not started"); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/utils/indexer/interface/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./id.js"; 2 | export * from "./query.js"; 3 | export * from "./index-engine.js"; 4 | export * from "./utils.js"; 5 | export * from "./errors.js"; 6 | -------------------------------------------------------------------------------- /packages/utils/indexer/interface/test/id.spec.ts: -------------------------------------------------------------------------------- 1 | import { serialize } from "@dao-xyz/borsh"; 2 | import { expect } from "chai"; 3 | import { toId } from "../src/id.js"; 4 | import { getIdProperty, id } from "../src/utils.js"; 5 | 6 | describe("toId", () => { 7 | it("throws when given an unexpected index key", () => { 8 | expect(() => toId(undefined as any)).to.throw( 9 | "Unexpected index key: undefined, expected: string, number, bigint or Uint8Array", 10 | ); 11 | }); 12 | }); 13 | 14 | describe("id decorator", () => { 15 | it("should assign the property to be the id of the object for indexing", () => { 16 | // Arrange 17 | class Test { 18 | @id({ type: "string" }) 19 | xyz: string; 20 | 21 | constructor() { 22 | this.xyz = "abc"; 23 | } 24 | } 25 | 26 | expect(getIdProperty(Test)).to.deep.equal(["xyz"]); 27 | 28 | // check that serialization still work 29 | 30 | const obj = new Test(); 31 | expect(serialize(obj)).to.deep.equal( 32 | new Uint8Array([3, 0, 0, 0, 97, 98, 99]), 33 | ); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/utils/indexer/interface/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "outDir": "dist", 7 | "strictFunctionTypes": true 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/indexer/simple/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/utils/indexer/simple/benchmark/index.ts: -------------------------------------------------------------------------------- 1 | import { benchmarks } from "@peerbit/indexer-tests"; 2 | import { create } from "../src/index.js"; 3 | 4 | // Run with "node --loader ts-node/esm ./benchmark/index.ts" 5 | 6 | await benchmarks(create, "transient"); 7 | -------------------------------------------------------------------------------- /packages/utils/indexer/simple/test/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { tests } from "@peerbit/indexer-tests"; 2 | import { create } from "../src"; 3 | 4 | describe("all", () => { 5 | tests(create, "transient", { 6 | shapingSupported: false, 7 | u64SumSupported: true, 8 | iteratorsMutable: false, 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/utils/indexer/simple/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "outDir": "dist", 7 | "checkJs": false 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/indexer/sqlite3/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/utils/indexer/sqlite3/benchmark/index.ts: -------------------------------------------------------------------------------- 1 | import { benchmarks } from "@peerbit/indexer-tests"; 2 | import { create } from "../src/index.js"; 3 | 4 | // Run with "node --loader ts-node/esm ./benchmark/index.ts" 5 | 6 | await benchmarks(create, "transient"); 7 | await benchmarks(create, "persist"); 8 | -------------------------------------------------------------------------------- /packages/utils/indexer/sqlite3/src/index.ts: -------------------------------------------------------------------------------- 1 | import { BinaryWriter } from "@dao-xyz/borsh"; 2 | import { sha256Sync, toBase58 } from "@peerbit/crypto"; 3 | import { SQLLiteIndex, SQLiteIndices } from "./engine.js"; 4 | import { create as sqlite3 } from "./sqlite3.js"; 5 | 6 | export const encodeName = (name: string): string => { 7 | const writer = new BinaryWriter(); 8 | writer.string(name); 9 | return toBase58(sha256Sync(writer.finalize())); 10 | }; 11 | 12 | const create = async (directory?: string): Promise => { 13 | const db = await sqlite3(directory); 14 | return new SQLiteIndices({ db }); 15 | }; 16 | export { create, SQLiteIndices, SQLLiteIndex }; 17 | -------------------------------------------------------------------------------- /packages/utils/indexer/sqlite3/test/fixtures.ts: -------------------------------------------------------------------------------- 1 | import { field, variant } from "@dao-xyz/borsh"; 2 | 3 | export class DocumentNoVariant { 4 | @field({ type: "u8" }) 5 | id: number; 6 | 7 | constructor(obj: any) { 8 | this.id = obj.id; 9 | } 10 | } 11 | 12 | @variant(0) 13 | export class DocumentWithVariant { 14 | @field({ type: "u8" }) 15 | id: number; 16 | 17 | constructor(obj: any) { 18 | this.id = obj.id; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/utils/indexer/sqlite3/test/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { tests } from "@peerbit/indexer-tests"; 2 | import { create } from "../src/index.js"; 3 | 4 | describe("all", () => { 5 | tests(create, "persist", { 6 | shapingSupported: true, 7 | u64SumSupported: false, 8 | iteratorsMutable: true, 9 | }); 10 | tests(create, "transient", { 11 | shapingSupported: true, 12 | u64SumSupported: false, 13 | iteratorsMutable: true, 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/utils/indexer/sqlite3/test/schema.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { fromRowToObj, getTableName } from "../src/schema.js"; 3 | import { DocumentNoVariant, DocumentWithVariant } from "./fixtures.js"; 4 | 5 | describe("schema", () => { 6 | it("fromRowToObj", () => { 7 | const obj = { id: 1 }; 8 | const parsed = fromRowToObj(obj, DocumentNoVariant); 9 | expect(parsed).to.be.instanceOf(DocumentNoVariant); 10 | expect(parsed.id).to.equal(1); 11 | }); 12 | 13 | describe("table", () => { 14 | it("uses class for table name when no variant", () => { 15 | const table = getTableName(["scope"], DocumentNoVariant); 16 | expect(table).to.equal("scope__class_DocumentNoVariant"); 17 | }); 18 | 19 | it("uses variant for table name", () => { 20 | const table = getTableName(["scope"], DocumentWithVariant); 21 | expect(table).to.equal("scope__v_0"); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/utils/indexer/sqlite3/test/table.spec.ts: -------------------------------------------------------------------------------- 1 | import { field } from "@dao-xyz/borsh"; 2 | import { id } from "@peerbit/indexer-interface"; 3 | import { expect } from "chai"; 4 | import { SQLLiteIndex } from "../src/engine.js"; 5 | import { create } from "../src/index.js"; 6 | import { setup } from "./utils.js"; 7 | 8 | describe("table", () => { 9 | let index: Awaited>>; 10 | 11 | afterEach(async () => { 12 | await index.store.stop(); 13 | }); 14 | 15 | // TODO what is expected? if we do this, we can not migrate, on the other hand we get performance benefits 16 | it("can use reserved words", async () => { 17 | class DocumentWithFromProperty { 18 | @id({ type: "string" }) 19 | id: string; 20 | 21 | @field({ type: "string" }) 22 | from: string; 23 | 24 | constructor(id: string, from: string) { 25 | this.id = id; 26 | this.from = from; 27 | } 28 | } 29 | 30 | index = await setup({ schema: DocumentWithFromProperty }, create); 31 | const store = index.store as SQLLiteIndex; 32 | expect(store.tables.size).to.equal(1); 33 | await store.put(new DocumentWithFromProperty("1", "from")); 34 | 35 | const results = await store.iterate().all(); 36 | expect(results.length).to.equal(1); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /packages/utils/indexer/sqlite3/test/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type Index, 3 | type IndexEngineInitProperties, 4 | type Indices, 5 | getIdProperty, 6 | } from "@peerbit/indexer-interface"; 7 | 8 | export const setup = async >( 9 | properties: Partial> & { schema: any }, 10 | createIndicies: (directory?: string) => Indices | Promise, 11 | ): Promise<{ indices: Indices; store: Index; directory?: string }> => { 12 | const indices = await createIndicies(); 13 | await indices.start(); 14 | const indexProps: IndexEngineInitProperties = { 15 | ...{ 16 | indexBy: getIdProperty(properties.schema) || ["id"], 17 | }, 18 | ...properties, 19 | }; 20 | const store = await indices.init(indexProps); 21 | return { indices, store }; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/utils/indexer/sqlite3/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "checkJs": false, 5 | "experimentalDecorators": true, 6 | "emitDecoratorMetadata": true, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test", "benchmark"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/indexer/tests/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/utils/indexer/tests/src/benchmarks.browser.ts: -------------------------------------------------------------------------------- 1 | export const benchmarks = () => { 2 | /* TODO */ 3 | }; 4 | -------------------------------------------------------------------------------- /packages/utils/indexer/tests/src/index.ts: -------------------------------------------------------------------------------- 1 | export { tests } from "./tests.js"; 2 | export { benchmarks } from "./benchmarks.js"; 3 | -------------------------------------------------------------------------------- /packages/utils/indexer/tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "checkJs": false, 5 | "strict": false, 6 | "allowUnusedLabels": true, 7 | "noUnusedLocals": false, 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "strictNullChecks": false, 11 | "outDir": "dist" 12 | }, 13 | "include": ["src", "test"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/utils/keychain/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/utils/keychain/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@peerbit/keychain", 3 | "version": "1.0.29", 4 | "description": "Utility functions for keychain", 5 | "sideEffects": false, 6 | "type": "module", 7 | "types": "./dist/src/index.d.ts", 8 | "typesVersions": { 9 | "*": { 10 | "*": [ 11 | "*", 12 | "dist/*", 13 | "dist/src/*", 14 | "dist/src/*/index" 15 | ], 16 | "src/*": [ 17 | "*", 18 | "dist/*", 19 | "dist/src/*", 20 | "dist/src/*/index" 21 | ] 22 | } 23 | }, 24 | "files": [ 25 | "src", 26 | "dist", 27 | "!dist/test", 28 | "!**/*.tsbuildinfo" 29 | ], 30 | "exports": { 31 | ".": { 32 | "types": "./dist/src/index.d.ts", 33 | "import": "./dist/src/index.js" 34 | } 35 | }, 36 | "eslintConfig": { 37 | "extends": "peerbit", 38 | "parserOptions": { 39 | "project": true, 40 | "sourceType": "module" 41 | }, 42 | "ignorePatterns": [ 43 | "!.aegir.js", 44 | "test/ts-use", 45 | "*.d.ts" 46 | ] 47 | }, 48 | "publishConfig": { 49 | "access": "public" 50 | }, 51 | "scripts": { 52 | "clean": "aegir clean", 53 | "build": "aegir build --no-bundle", 54 | "test": "aegir test", 55 | "lint": "aegir lint" 56 | }, 57 | "author": "dao.xyz", 58 | "license": "MIT", 59 | "dependencies": { 60 | "@peerbit/crypto": "^2.3.9", 61 | "@peerbit/any-store": "^2.1.11" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /packages/utils/keychain/test/encryption.spec.ts: -------------------------------------------------------------------------------- 1 | import { DecryptedThing, X25519Keypair } from "@peerbit/crypto"; 2 | import { expect } from "chai"; 3 | import { DefaultKeychain } from "../src/index.js"; 4 | 5 | describe("encryption", () => { 6 | it("decryptProvider", async () => { 7 | const senderKey = await X25519Keypair.create(); 8 | 9 | const receiverKey1 = await X25519Keypair.create(); 10 | const receiverKeychain1 = new DefaultKeychain(); 11 | await receiverKeychain1.import({ keypair: receiverKey1 }); 12 | 13 | const receiverKey2 = await X25519Keypair.create(); 14 | const receiverKeychain2 = new DefaultKeychain(); 15 | await receiverKeychain2.import({ keypair: receiverKey2 }); 16 | 17 | const data = new Uint8Array([1, 2, 3]); 18 | const decrypted = new DecryptedThing({ 19 | data, 20 | }); 21 | 22 | const encrypted = await decrypted.encrypt(senderKey, [ 23 | receiverKey1.publicKey, 24 | receiverKey2.publicKey, 25 | ]); 26 | 27 | encrypted._decrypted = undefined; 28 | 29 | const decryptedFromEncrypted1 = await encrypted.decrypt(receiverKeychain1); 30 | expect(decryptedFromEncrypted1._data).to.deep.equal(data); 31 | 32 | const decryptedFromEncrypted2 = await encrypted.decrypt(receiverKeychain2); 33 | expect(decryptedFromEncrypted2._data).to.deep.equal(data); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/utils/keychain/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/logger/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib -------------------------------------------------------------------------------- /packages/utils/logger/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2018 shamb0t 4 | Copyright (c) 2018 Haja Networks Oy 5 | Copyright (c) 2020 dao.xyz 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | 25 | -------------------------------------------------------------------------------- /packages/utils/logger/benchmark/index.ts: -------------------------------------------------------------------------------- 1 | import { logger as lLogger } from "@libp2p/logger"; 2 | import * as B from "tinybench"; 3 | import { logger as pLogger } from "../src/index.js"; 4 | 5 | //node --loader ts-node/esm ./benchmark/index.ts 6 | 7 | let libp2pLogger = lLogger("test"); 8 | libp2pLogger.error("Error works as expected from libp2p"); 9 | let peerbitLogger = pLogger({ module: "test" }); 10 | peerbitLogger.level = "error"; 11 | peerbitLogger.error("Error works as expected Peerbit!"); 12 | 13 | const suite = new B.Bench(); 14 | await suite 15 | .add("libp2p-logger", () => { 16 | libp2pLogger("hello"); 17 | }) 18 | .add("peerbit-logger", () => { 19 | peerbitLogger.info("hello"); 20 | }) 21 | .run(); 22 | 23 | console.table(suite.table()); 24 | -------------------------------------------------------------------------------- /packages/utils/logger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@peerbit/logger", 3 | "version": "1.0.3", 4 | "description": "Logging utils", 5 | "sideEffects": false, 6 | "type": "module", 7 | "types": "./dist/src/index.d.ts", 8 | "typesVersions": { 9 | "*": { 10 | "*": [ 11 | "*", 12 | "dist/*", 13 | "dist/src/*", 14 | "dist/src/*/index" 15 | ], 16 | "src/*": [ 17 | "*", 18 | "dist/*", 19 | "dist/src/*", 20 | "dist/src/*/index" 21 | ] 22 | } 23 | }, 24 | "files": [ 25 | "src", 26 | "dist", 27 | "!dist/test", 28 | "!**/*.tsbuildinfo" 29 | ], 30 | "exports": { 31 | ".": { 32 | "types": "./dist/src/index.d.ts", 33 | "import": "./dist/src/index.js" 34 | } 35 | }, 36 | "eslintConfig": { 37 | "extends": "peerbit", 38 | "parserOptions": { 39 | "project": true, 40 | "sourceType": "module" 41 | }, 42 | "ignorePatterns": [ 43 | "!.aegir.js", 44 | "test/ts-use", 45 | "*.d.ts" 46 | ] 47 | }, 48 | "publishConfig": { 49 | "access": "public" 50 | }, 51 | "dependencies": { 52 | "pino": "^8.14.1" 53 | }, 54 | "scripts": { 55 | "clean": "aegir clean", 56 | "build": "aegir build --no-bundle", 57 | "test": "aegir test --target node", 58 | "lint": "aegir lint" 59 | }, 60 | "author": "dao.xyz", 61 | "license": "MIT" 62 | } 63 | -------------------------------------------------------------------------------- /packages/utils/logger/src/index.ts: -------------------------------------------------------------------------------- 1 | import pino from "pino"; 2 | 3 | const isNode = typeof window === "undefined"; 4 | 5 | export const getEnv = (key: any) => { 6 | if (isNode) { 7 | // node 8 | return process.env[key]; 9 | } 10 | // browser 11 | return window.process?.env?.[key]; 12 | }; 13 | export const getLogLevel = () => { 14 | const level = getEnv("LOG_LEVEL") || getEnv("REACT_APP_LOG_LEVEL"); 15 | if (!level) { 16 | return undefined; 17 | } 18 | const levels = ["fatal", "error", "warn", "info", "debug", "trace"]; 19 | if (!levels.includes(level)) { 20 | throw new Error( 21 | "Unexpected LOG_LEVEL: " + 22 | level + 23 | ". Expecting one of: " + 24 | JSON.stringify(levels), 25 | ); 26 | } 27 | return level; 28 | }; 29 | 30 | const logger = (options?: { module?: string; level?: string }) => { 31 | let logger = pino(); 32 | if (options?.module) { 33 | logger = logger.child({ module: options.module }); 34 | } 35 | if (options?.level) { 36 | logger.level = options.level; 37 | } else { 38 | const logLevel = getLogLevel(); 39 | if (logLevel) { 40 | logger.level = logLevel; 41 | } 42 | } 43 | return logger; 44 | }; 45 | 46 | export { logger }; 47 | -------------------------------------------------------------------------------- /packages/utils/logger/test/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { logger } from "../src/index.js"; 3 | 4 | describe("logger", () => { 5 | let reset: string | undefined; 6 | beforeEach(() => { 7 | reset = process.env.LOG_LEVEL; 8 | }); 9 | 10 | afterEach(() => { 11 | if (reset) { 12 | process.env.LOG_LEVEL = reset; 13 | } else { 14 | delete process.env.LOG_LEVEL; 15 | } 16 | }); 17 | it("can get log level", async () => { 18 | process.env.LOG_LEVEL = "fatal"; 19 | expect(logger().level).equal("fatal"); 20 | }); 21 | 22 | it("can handle undefined level", async () => { 23 | expect(logger().level).equal("info"); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /packages/utils/logger/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "strictNullChecks": false, 7 | "outDir": "dist" 8 | }, 9 | "include": ["src", "test"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/rateless-iblt/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | pkg -------------------------------------------------------------------------------- /packages/utils/rateless-iblt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "riblt" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | description = "Rust port of RIBLT library by yang1996" 7 | repository = "https://github.com/Intersubjective/riblt-rust" 8 | readme = "README.md" 9 | exclude = [ 10 | "TODO", 11 | "mapping_ref.txt", 12 | ] 13 | 14 | [lib] 15 | crate-type = ["cdylib", "rlib"] 16 | 17 | [[bench]] 18 | name = "riblt_bench" 19 | harness = false 20 | 21 | [dev-dependencies] 22 | criterion = "0.5.1" 23 | sha2 = "0.10.8" 24 | 25 | [dependencies] 26 | js-sys = "0.3.76" 27 | wasm-bindgen = { version = "0.2.99" } 28 | 29 | 30 | [package.metadata.wasm-pack.profile.release] 31 | wasm-opt = false 32 | -------------------------------------------------------------------------------- /packages/utils/rateless-iblt/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Intersubjective 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/utils/rateless-iblt/TODO: -------------------------------------------------------------------------------- 1 | To-Do list 2 | 3 | 1. Get rid of bloated dependencies: criterion, sha2 4 | 2. Sketch code is never used and doesn't have the test coverage. Consider removing it or add tests. 5 | 3. Investigate mapping determinism. 6 | -------------------------------------------------------------------------------- /packages/utils/rateless-iblt/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests; 3 | 4 | pub mod encoding; 5 | pub mod sketch; 6 | pub mod testing; 7 | pub mod wasm; 8 | -------------------------------------------------------------------------------- /packages/utils/rateless-iblt/src/testing.rs: -------------------------------------------------------------------------------- 1 | use crate::encoding::Symbol; 2 | 3 | #[allow(deprecated)] 4 | use std::hash::{Hasher, SipHasher}; 5 | 6 | const TEST_SYMBOL_SIZE: usize = 64; 7 | 8 | pub type TestSymbol = [u8; TEST_SYMBOL_SIZE]; 9 | 10 | pub fn new_test_symbol(x: u64) -> TestSymbol { 11 | return core::array::from_fn::(|i| { 12 | x.checked_shr(8 * i as u32).unwrap_or(0) as u8 13 | }); 14 | } 15 | 16 | impl Symbol for TestSymbol { 17 | fn zero() -> TestSymbol { 18 | return new_test_symbol(0); 19 | } 20 | 21 | fn xor(&self, other: &TestSymbol) -> TestSymbol { 22 | return core::array::from_fn(|i| self[i] ^ other[i]); 23 | } 24 | 25 | #[allow(deprecated)] 26 | fn hash(&self) -> u64 { 27 | let mut hasher = SipHasher::new_with_keys(567, 890); 28 | hasher.write(self); 29 | return hasher.finish(); 30 | } 31 | } 32 | 33 | pub type TestU64 = u64; 34 | 35 | impl Symbol for TestU64 { 36 | fn zero() -> TestU64 { 37 | return 0; 38 | } 39 | 40 | fn xor(&self, other: &TestU64) -> TestU64 { 41 | return self ^ other; 42 | } 43 | 44 | #[allow(deprecated)] 45 | fn hash(&self) -> u64 { 46 | let mut hasher = SipHasher::new_with_keys(123, 456); 47 | hasher.write_u64(*self); 48 | return hasher.finish(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/utils/rateless-iblt/src_js/index.js: -------------------------------------------------------------------------------- 1 | import "./wasm-init.js"; 2 | 3 | export { DecoderWrapper, EncoderWrapper, initSync } from "./rateless_iblt.js"; 4 | -------------------------------------------------------------------------------- /packages/utils/rateless-iblt/src_js/wasm-init.browser.js: -------------------------------------------------------------------------------- 1 | // nothing to do since 'fetch' works as expected in the browsere 2 | import init from "./rateless_iblt.js"; 3 | 4 | await init(new URL("/peerbit/rateless_iblt_bg.wasm", import.meta.url)); 5 | -------------------------------------------------------------------------------- /packages/utils/rateless-iblt/src_js/wasm-init.js: -------------------------------------------------------------------------------- 1 | // Override globalThis.fetch to intercept .wasm requests 2 | import { readFile } from "fs/promises"; 3 | import init from "./rateless_iblt.js"; 4 | 5 | const defaultFetch = globalThis.fetch.bind(globalThis); 6 | globalThis.fetch = async (url, options) => { 7 | // If you have multiple wasm files, you might use some logic to handle them. 8 | // Here, we assume any request ending in `.wasm` is local on disk at the same path. 9 | if (url.toString().endsWith(".wasm")) { 10 | // Return a NodeResponse that looks enough like a fetch Response 11 | return readFile(url); 12 | } 13 | 14 | return defaultFetch(url, options); 15 | }; 16 | 17 | await init(); 18 | -------------------------------------------------------------------------------- /packages/utils/time/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | lib -------------------------------------------------------------------------------- /packages/utils/time/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 dao.xyz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /packages/utils/time/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@peerbit/time", 3 | "version": "2.1.0", 4 | "description": "Utility functions for time", 5 | "type": "module", 6 | "sideEffects": false, 7 | "types": "./dist/src/index.d.ts", 8 | "typesVersions": { 9 | "*": { 10 | "*": [ 11 | "*", 12 | "dist/*", 13 | "dist/src/*", 14 | "dist/src/*/index" 15 | ], 16 | "src/*": [ 17 | "*", 18 | "dist/*", 19 | "dist/src/*", 20 | "dist/src/*/index" 21 | ] 22 | } 23 | }, 24 | "files": [ 25 | "src", 26 | "dist", 27 | "!dist/test", 28 | "!**/*.tsbuildinfo" 29 | ], 30 | "exports": { 31 | ".": { 32 | "types": "./dist/src/index.d.ts", 33 | "import": "./dist/src/index.js" 34 | } 35 | }, 36 | "eslintConfig": { 37 | "extends": "peerbit", 38 | "parserOptions": { 39 | "project": true, 40 | "sourceType": "module" 41 | }, 42 | "ignorePatterns": [ 43 | "!.aegir.js", 44 | "test/ts-use", 45 | "*.d.ts" 46 | ] 47 | }, 48 | "browser": { 49 | "./dist/src/hrtime.js": "./dist/src/hrtime.browser.js" 50 | }, 51 | "publishConfig": { 52 | "access": "public" 53 | }, 54 | "scripts": { 55 | "clean": "aegir clean", 56 | "build": "aegir build --no-bundle", 57 | "test": "aegir test", 58 | "lint": "aegir lint" 59 | }, 60 | "author": "dao.xyz", 61 | "license": "MIT" 62 | } 63 | -------------------------------------------------------------------------------- /packages/utils/time/src/hrtime.ts: -------------------------------------------------------------------------------- 1 | const hrtime = process.hrtime; 2 | export { hrtime }; 3 | -------------------------------------------------------------------------------- /packages/utils/time/src/index.ts: -------------------------------------------------------------------------------- 1 | import { hrtime } from "./hrtime.js"; 2 | 3 | export * from "./aggregators.js"; 4 | export * from "./wait.js"; 5 | export * from "./metrics.js"; 6 | export { hrtime }; 7 | -------------------------------------------------------------------------------- /packages/utils/time/src/metrics.ts: -------------------------------------------------------------------------------- 1 | import { hrtime } from "./hrtime.js"; 2 | 3 | export class MovingAverageTracker { 4 | private lastTS: bigint; 5 | 6 | value = 0; 7 | 8 | constructor(readonly tau = 10) { 9 | this.lastTS = hrtime.bigint(); 10 | } 11 | 12 | add(number: number) { 13 | const now = hrtime.bigint(); 14 | let diff = Number(now - this.lastTS); 15 | if (diff <= 0) { 16 | diff = 1; // prevent Math.exp below become NaN 17 | } 18 | const dt = diff / 1e9; 19 | this.lastTS = now; 20 | const alphaT = 1 - Math.exp(-dt / this.tau); 21 | this.value = (1 - alphaT) * this.value + (alphaT * number) / dt; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/utils/time/test/metrics.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { waitForResolved } from "../src/index.js"; 3 | import { MovingAverageTracker } from "../src/metrics.js"; 4 | 5 | describe("metrics", () => { 6 | it("moving averiage", async () => { 7 | const ma = new MovingAverageTracker(1); 8 | let done = false; 9 | const interval = setInterval(() => { 10 | ma.add(100); // 100 per 100 ms => 1000 per second 11 | try { 12 | expect(ma.value).greaterThan(850); 13 | expect(ma.value).lessThan(1100); 14 | clearInterval(interval); 15 | done = true; 16 | } catch (error) {} 17 | }, 100); 18 | 19 | await waitForResolved(() => expect(done).to.be.true); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /packages/utils/time/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "outDir": "dist" 7 | }, 8 | "include": ["src", "test"] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "checkJs": false, 5 | "strictPropertyInitialization": false, 6 | "experimentalDecorators": true, 7 | "emitDecoratorMetadata": true, 8 | "outDir": "dist" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "checkJs": false, 5 | "strictPropertyInitialization": false, 6 | "experimentalDecorators": true, 7 | "emitDecoratorMetadata": true, 8 | "outDir": "dist" 9 | }, 10 | "include": ["src", "test"] 11 | } 12 | --------------------------------------------------------------------------------