reorganizing packages

feat/orm-diffs
Niko PLP 2 days ago
parent 1039c2694d
commit bf8bdd94b9
  1. 124
      Cargo.lock
  2. 5
      Cargo.toml
  3. 114
      DEV.md
  4. 8
      README.md
  5. 3
      app/nextgraph/.gitignore
  6. 23
      app/nextgraph/README.md
  7. 174
      app/nextgraph/index.html
  8. 26
      app/nextgraph/package.json
  9. 32
      app/nextgraph/prepare-web-file.cjs
  10. 8
      app/nextgraph/src-tauri/Cargo.toml
  11. 1089
      app/nextgraph/src-tauri/src/lib.rs
  12. 2
      app/nextgraph/src-tauri/src/main.rs
  13. 8
      app/nextgraph/src-tauri/tauri.conf.json
  14. 40
      app/nextgraph/src/App.svelte
  15. 16
      app/nextgraph/src/assets/logo.svg
  16. 34
      app/nextgraph/src/main-web.ts
  17. 13
      app/nextgraph/src/main.ts
  18. 335
      app/nextgraph/src/native-api.ts
  19. 5
      app/nextgraph/svelte.config.js
  20. 2
      app/nextgraph/tsconfig.json
  21. 190
      app/nextgraph/vite.config.ts
  22. 8
      bin/ngd/README.md
  23. 2
      engine/broker/auth/src/main.ts
  24. 4
      engine/broker/src/server_ws.rs
  25. 2
      infra/ngaccount/web/package.json
  26. 2
      infra/ngnet/redir/package.json
  27. 5
      package.json
  28. 920
      pnpm-lock.yaml
  29. 86
      sdk/js/DEV.md
  30. 6
      sdk/js/README.md
  31. 65
      sdk/js/lib-wasm/DEV.md
  32. 59
      sdk/js/lib-wasm/jsland/browser.js
  33. 181
      sdk/python/.github/workflows/CI.yml
  34. 72
      sdk/python/.gitignore
  35. 25
      sdk/python/Cargo.toml
  36. 63
      sdk/python/README.md
  37. 17
      sdk/python/pyproject.toml
  38. 167
      sdk/python/src/lib.rs
  39. 21
      sdk/python/test.py
  40. 15
      sdk/rust/README.md

124
Cargo.lock generated

@ -6,17 +6,23 @@ version = 3
name = "NextGraph"
version = "0.1.2"
dependencies = [
"async-std",
"nextgraph",
"ng-async-tungstenite",
"ng-net",
"ng-repo",
"ng-wallet",
"oxrdf",
"serde",
"serde_bare",
"serde_bytes",
"serde_json",
"sys-locale",
"tauri",
"tauri-build",
"tauri-plugin-barcode-scanner",
"tauri-plugin-opener",
"zeroize",
]
[[package]]
@ -2922,6 +2928,12 @@ dependencies = [
"serde_core",
]
[[package]]
name = "indoc"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
[[package]]
name = "infer"
version = "0.19.0"
@ -3818,6 +3830,18 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "ng-sdk-python"
version = "0.1.2"
dependencies = [
"async-std",
"nextgraph",
"pyo3",
"pyo3-async-runtimes",
"pythonize",
"serde",
]
[[package]]
name = "ng-storage-rocksdb"
version = "0.1.2"
@ -4142,7 +4166,7 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro-crate 3.4.0",
"proc-macro2",
"quote",
"syn 2.0.106",
@ -5015,6 +5039,12 @@ dependencies = [
"universal-hash",
]
[[package]]
name = "portable-atomic"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
[[package]]
name = "potential_utf"
version = "0.1.3"
@ -5138,6 +5168,92 @@ version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
[[package]]
name = "pyo3"
version = "0.23.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872"
dependencies = [
"cfg-if",
"indoc",
"libc",
"memoffset",
"once_cell",
"portable-atomic",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
"unindent",
]
[[package]]
name = "pyo3-async-runtimes"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "977dc837525cfd22919ba6a831413854beb7c99a256c03bf8624ad707e45810e"
dependencies = [
"async-std",
"futures",
"once_cell",
"pin-project-lite",
"pyo3",
]
[[package]]
name = "pyo3-build-config"
version = "0.23.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94f6cbe86ef3bf18998d9df6e0f3fc1050a8c5efa409bf712e661a4366e010fb"
dependencies = [
"once_cell",
"target-lexicon",
]
[[package]]
name = "pyo3-ffi"
version = "0.23.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9f1b4c431c0bb1c8fb0a338709859eed0d030ff6daa34368d3b152a63dfdd8d"
dependencies = [
"libc",
"pyo3-build-config",
]
[[package]]
name = "pyo3-macros"
version = "0.23.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbc2201328f63c4710f68abdf653c89d8dbc2858b88c5d88b0ff38a75288a9da"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 2.0.106",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.23.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fca6726ad0f3da9c9de093d6f116a93c1a38e417ed73bf138472cf4064f72028"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"pyo3-build-config",
"quote",
"syn 2.0.106",
]
[[package]]
name = "pythonize"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91a6ee7a084f913f98d70cdc3ebec07e852b735ae3059a1500db2661265da9ff"
dependencies = [
"pyo3",
"serde",
]
[[package]]
name = "qoi"
version = "0.4.1"
@ -7237,6 +7353,12 @@ version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unindent"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
[[package]]
name = "unique_id"
version = "0.1.7"

@ -11,6 +11,7 @@ members = [
"engine/oxigraph",
"sdk/rust",
"sdk/js/lib-wasm",
"sdk/python",
"bin/ngd",
"bin/ngcli",
"infra/ngaccount",
@ -73,3 +74,7 @@ opt-level = 2
# tauri = { git = "https://git.nextgraph.org/NextGraph/tauri.git", branch="alpha.11-nextgraph", features = ["no-ipc-custom-protocol"] }
[workspace.dependencies]
[workspace.metadata.scripts]
libwasm = "cd sdk/js/lib-wasm && cargo run-script app && cd ../../.."

114
DEV.md

@ -26,16 +26,7 @@ git clone git@git.nextgraph.org:NextGraph/nextgraph-rs.git
// or if you don't have a git account with us: git clone https://git.nextgraph.org/NextGraph/nextgraph-rs.git
cd nextgraph-rs
npm install -g pnpm
cd sdk/lib-wasm
cargo run-script app
cd ../..
cd helpers/wasm-tools
cargo run-script app
cd ../..
pnpm -C ./ng-app install
pnpm -C ./ng-app webfilebuild
pnpm -C ./helpers/app-auth install
pnpm -C ./helpers/app-auth build
pnpm buildfront
```
For building the native apps, see the [ng-app/README](ng-app/README.md)
@ -50,23 +41,29 @@ If you prefer to change the base directory, use the argument `--base [PATH]` whe
cargo run -p ngd -- -vv --save-key -l 14400
```
If you are developing also the front-end, you should run it with this command in a separate terminal:
```
cd ng-app
pnpm -C ../helpers/net-auth builddev
pnpm -C ../helpers/app-auth builddev
pnpm -C ../helpers/net-bootstrap builddev
pnpm webdev
```
In the logs/output of ngd, you will see an invitation link that you should open in your web browser. If there are many links, choose the one that starts with `http://localhost:`, and if you run a local front-end, replace the prefix `http://localhost:14400/` with `http://localhost:1421/` before you open the link in your browser.
The computer you use to open the link should have direct access to the ngd server on localhost. In most of the cases, it will work, as you are running ngd on localhost. If you are running ngd in a docker container, then you need to give access to the container to the local network of the host by using `docker run --network="host"`. see more here https://docs.docker.com/network/drivers/host/
Follow the steps on the screen to create your wallet :)
Once your ngd server will run in your dev env, replace the string in `nextgraph/src/local_broker_dev_env.rs` with the actual PEER ID of your ngd server that is displayed when you first start `ngd`, with a line starting with `INFO ngd] PeerId of node:`.
Once your ngd server will run in your dev env, replace the string in `sdk/rust/src/local_broker_dev_env.rs` with the actual PEER ID of your ngd server that is displayed when you first start `ngd`, with a line starting with `INFO ngd] PeerId of node:`. This step is needed if you want to test or develop the import of wallet with QRCode.
More details about usage of ngd [here](bin/ngd/README.md).
### If you are developing the front-end too
If you are also developing the front-end of NextGraph app, you should run it with this command in a separate terminal:
```
// run this only once, from root folder:
pnpm buildfrontdev
// to start the front-end for development
cd app/nextgraph
pnpm webdev
```
more details about developing the front-end [here](app/nextgraph/README.md).
### Using ngcli with the account you just created
@ -107,23 +104,37 @@ Then you need to stop your ngd and start it again with the additional option :
### Packages
The crates are organized as follow :
- [nextgraph](nextgraph/README.md) : Client library. Use this crate to embed NextGraph client in your Rust application
- [ngcli](ngcli/README.md) : CLI tool to manipulate the local documents and repos and administrate the server
- [ngd](ngd/README.md) : binary executable of the daemon (that can run a broker, verifier and/or Rust services)
- [ng-app](ng-app/README.md) : all the native apps, based on Tauri, and the official web app.
- [lib-wasm](lib-wasm/DEV.md) : contains the JS SDK, with example for: web app, react app, or node service.
- [ng-sdk-python](ng-sdk-python/README.md) : contains the Python SDK.
- ng-repo : Repositories common library
- ng-net : Network common library
- ng-oxigraph : Fork of OxiGraph. contains our CRDT of RDF
- ng-verifier : Verifier library, that exposes the document API to the app
- ng-wallet : keeps the secret keys of all identities of the user in a safe wallet
- ng-broker : Core and Server Broker library
- ng-client-ws : Websocket client library
- ng-storage-rocksdb : RocksDB backed stores. see also dependency [repo here](https://git.nextgraph.org/NextGraph/rust-rocksdb)
- helpers : all kind of servers and front end code needed for our infrastructure.
The crates and packages are organized as follow :
- app : the main application of NextGraph
- ui-common : common UI elements
- [nextgraph](app/nextgraph/README.md)
- src-tauri : the Tauri based native apps
- src : the Web-based app
- bin : the binaries
- [ngcli](bin/ngcli/README.md) : CLI tool to manipulate the local documents and repos and administrate the server
- [ngd](bin/ngd/README.md) : binary executable of the daemon (that runs a broker, the verifier and additional Rust services)
- engine : the core engine including NGproto
- repo : Repositories common library
- net : Network common library
- oxigraph : Fork of OxiGraph. contains our CRDT of RDF
- verifier : Verifier library, that exposes the document API to the app
- wallet : keeps the secret keys of all identities of the user in a safe wallet
- broker : Core and Server Broker library
- client-ws : Websocket client library
- storage-rocksdb : RocksDB backed stores. see also dependency [repo here](https://git.nextgraph.org/NextGraph/rust-rocksdb)
- infra : tools and binaries for infrastructure of the platform
- ngaccount : broker service provider (BSP) account manager
- ngapp : server of the web app used by self-hosters on the public web
- ngnet : server of nextgraph.net that shelps with authentication of third-party web apps.
- sdk
- [js](sdk/js/README.md)
- api-web : the web version of the API
- [lib-wasm](sdk/js/lib-wasm/DEV.md) : the WASM library used by api-web
- [examples](sdk/js/DEV.md) : example for: web app, React/Svelte app, or node service
- alien-deepsignals, shex-orm and signals : used by the ORM mechanism
- [rust](sdk/rust/README.md) : Client library. Use this crate to embed NextGraph client in your Rust application
- [python](sdk/python/README.md) : contains the Python SDK.
### Test
@ -173,13 +184,8 @@ You need to freshly built it from source, following those instructions:
```
cargo install cargo-run-script
npm install -g pnpm
cd lib-wasm
cargo run-script app
cd ..
pnpm -C ./ng-app install
pnpm -C ./ng-app webfilebuild
pnpm -C ./helpers/app-auth install
pnpm -C ./helpers/app-auth build
cargo run-script libwasm
pnpm buildfront
```
then build the ngd daemon
@ -198,9 +204,9 @@ cargo build -r -p ngcli
you can then use the binary `target/release/ngcli`
For usage, see the documentation [here](ngd/README.md).
For usage, see the documentation [here](bin/ngd/README.md).
For building the apps, see this [documentation](ng-app/README.md).
For building the native apps, see this [documentation](app/nextgraph/README.md).
#### OpenBSD
@ -239,3 +245,17 @@ The generated documentation can be found in `target/doc/nextgraph`.
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you shall be dual licensed as below, without any
additional terms or conditions.
## License
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
`SPDX-License-Identifier: Apache-2.0 OR MIT`
---
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/assure) and the [NGI Zero Commons Fund](https://nlnet.nl/commonsfund/), both funds established by [NLnet](https://nlnet.nl/) Foundation with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreements No 957073 and No 101092990, respectively.

@ -36,7 +36,7 @@ And our community forum where you can ask questions is here [https://forum.nextg
## How to use NextGraph App & Platform
NextGraph is in alpha release!
NextGraph is in alpha release.
You can try it online or by installing the apps. Please follow our [Getting started](https://docs.nextgraph.org/en/getting-started/) guide .
@ -54,9 +54,9 @@ See our [contributor's guide](DEV.md)
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
`SPDX-License-Identifier: Apache-2.0 OR MIT`

@ -9,8 +9,9 @@ lerna-debug.log*
node_modules
dist
dist-ssr
dist-web
*.local
public_dev
# Editor directories and files
.vscode/*

@ -18,13 +18,10 @@ pnpm install @tauri-apps/cli
## Web
prerequisites: compile the local SDK
prerequisites: compile the local JS/WASM SDK
```
cd ../ng-sdk-js
cargo install cargo-run-script
cargo run-script app
cd ../ng-app
pnpm libwasm
```
#### Dev
@ -32,8 +29,7 @@ cd ../ng-app
First time:
```
pnpm -C ../helpers/net-auth builddev
pnpm -C ../helpers/net-bootstrap builddev
pnpm buildfrontdev
```
Then run your local front-end:
@ -45,21 +41,10 @@ pnpm webdev
#### Prod
this will produce a single html file embedding all the resources. this is what you need for production
```
pnpm webfilebuild
// single file is available in dist-file/index.html
```
alternatively, to obtain a regular dist folder with all resources in separate files (we dont use it anymore):
this will produce a single html file embedding all the resources. this is what ngd broker needs for production
```
pnpm webbuild
// then the application is available in dist-web folder
// can be served with:
cd dist-web ; python3 -m http.server
```
## Desktop

@ -1,14 +1,182 @@
<!--
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="/src/styles.css" />
<link
rel="icon"
type="image/svg+xml"
href="data:image/svg+xml;base64,
PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMjUg
MjI1Ij48Y2lyY2xlIGN4PSIxMDkuODgxIiBjeT0iMTEyLjkwNSIgcj0iMTA2Ljk4IiBzdHlsZT0i
ZmlsbDogcmdiKDI1NSwgMjU1LCAyNTUpOyBzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMC4y
NjgzNzU7Ij48L2NpcmNsZT48cGF0aCBkPSJNOTguMzQzIDE5MC4yNjFjLTE3Ljk0LTIuNzI3LTMz
LjMzMS0xMC42ODMtNDUuNzM1LTIzLjYzOC0xNC4wMDYtMTQuNjI5LTIxLjQzLTMzLjIxLTIxLjQz
LTUzLjYzNSAwLTEwLjIxOCAxLjctMTkuNDQ0IDUuMjIxLTI4LjMzMiA0LjI4Ny0xMC44MiAxMC4w
MzgtMTkuMzkgMTguNTM1LTI3LjYyMiA0LjczLTQuNTgyIDYuNjA3LTYuMTA3IDExLjI4MS05LjE2
MyAxMS45LTcuNzggMjQuMTc0LTExLjg4IDM4LjA5Ni0xMi43MjUgMTkuODA1LTEuMjAxIDM5LjEx
MiA1LjExMyA1NC42MDMgMTcuODYgMS41MDcgMS4yNCAyLjczIDIuMzU4IDIuNzE2IDIuNDg2LS4w
MTMuMTI4LTMuODU4IDMuNjM1LTguNTQ0IDcuNzkzLTQuNjg2IDQuMTU3LTEwLjA0NyA4Ljk2Mi0x
MS45MTQgMTAuNjc3LTEuODY2IDEuNzE1LTMuNTQgMy4xMTktMy43MjEgMy4xMTktLjE4MSAwLTEu
NC0uNzQ2LTIuNzEtMS42NTYtNy41My01LjIzOS0xNS45OTQtNy44MjItMjUuNjI1LTcuODIyLTEy
LjczMiAwLTIzLjI1IDQuMzM4LTMyLjE0NCAxMy4yNTctNi4zOTYgNi40MTQtMTAuNzA0IDE0LjU1
Ni0xMi41IDIzLjYyNC0uNjkxIDMuNDg4LS42OSAxMy41My4wMDIgMTcuMDA5IDMuNzA1IDE4LjYy
NiAxOC4zMTggMzMuMTAyIDM2LjY0MiAzNi4yOTcgNC4xNjQuNzI2IDExLjk4LjcxMiAxNS45OS0u
MDI4IDE0LjAzMi0yLjU5NCAyNS44Ni0xMS4zNjggMzIuMjY1LTIzLjkzNi43NzQtMS41MTkgMS4y
Ni0yLjg4NSAxLjA4LTMuMDM2LS4xNzgtLjE1Mi02Ljg3NC0xLjE3OC0xNC44NzctMi4yODEtOS43
OC0xLjM0OC0xNC45MjQtMi4yMTQtMTUuNjg1LTIuNjQxLTEuNTItLjg1NC0yLjgzNi0yLjg4OC0y
LjgzNi00LjM4NiAwLTEuMTczIDIuMDI3LTE1Ljg2OSAyLjQ5LTE4LjA2LjI5OC0xLjQwMSAyLjQy
Ni0zLjQ5MyAzLjg0NC0zLjc3Ny42MjItLjEyNCA4LjgyNy44NTYgMTguMjggMi4xODQgOS40MzQg
MS4zMjUgMTcuMjYzIDIuMjk0IDE3LjM5OSAyLjE1NC4xMzYtLjE0IDEuMTE4LTYuNTQ4IDIuMTgz
LTE0LjI0IDEuMTA4LTggMi4yMDQtMTQuNjAyIDIuNTYyLTE1LjQyNi4zNDQtLjc5MyAxLjExLTEu
ODUgMS43MDMtMi4zNDggMi4wNjMtMS43MzYgMy4xNDMtMS43ODUgMTIuMjA0LS41NTMgOS42MzYg
MS4zMSAxMC43MDkgMS41NjIgMTIuMjggMi44ODUgMS42NDQgMS4zODMgMi4yNzQgMi44MSAyLjI2
IDUuMTIzLS4wMDcgMS4xMDItLjkyMiA4LjI5Ny0yLjAzMyAxNS45ODktMS4xMTIgNy42OTEtMS45
NzIgMTQuMDQtMS45MTIgMTQuMTA5LjA2MS4wNjggNy4xNjcgMS4xMTEgMTUuNzkyIDIuMzE4IDEx
LjEwNSAxLjU1NCAxNi4wMDggMi4zODcgMTYuODAyIDIuODU2IDEuNTMuOTA0IDIuNDggMi42NDgg
Mi40NSA0LjQ5OC0uMDQ2IDIuODQ0LTIuNDEzIDE4LjEyMy0yLjk3NSAxOS4yMS0uNjYyIDEuMjgt
Mi42MDMgMi41NDgtMy45MjEgMi41NjItLjUyLjAwNS03Ljg3NS0uOTYtMTYuMzQ0LTIuMTQ0LTgu
NDctMS4xODUtMTUuNDc2LTIuMDc3LTE1LjU3LTEuOTgzLS4wOTQuMDk0LTEuMTg4IDcuMzQxLTIu
NDMxIDE2LjEwNi0xLjQ0IDEwLjE1My0yLjQ5OCAxNi40MzYtMi45MTYgMTcuMzE2LS43MjUgMS41
MjgtMi43NjIgMy4wNjMtNC41MzggMy40MTgtLjk1Ny4xOTEtMTAuOS0uOTI4LTEzLjU5OC0xLjUz
LS41NDgtLjEyMy0xLjg5Mi42NzItNC41MSAyLjY2NS0xMS4yNjMgOC41NzYtMjQuMzQyIDEzLjkx
LTM4LjM1NyAxNS42NDItNC40LjU0NC0xNS43MjcuNDMzLTE5Ljg1NC0uMTk1eiIgc3R5bGU9ImZp
bGw6IHJnYig3MywgMTE0LCAxNjUpOyBmaWxsLW9wYWNpdHk6IDE7IHN0cm9rZTogcmdiKDczLCAx
MTQsIDE2NSk7IHN0cm9rZS13aWR0aDogMC4zNzc5NzY7IHN0cm9rZS1vcGFjaXR5OiAxOyI+PC9w
YXRoPjwvc3ZnPg=="
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>NextGraph</title>
<script type="module" src="/src/main.ts" defer></script>
<meta property="og:title" content="NextGraph App - The New Internet Platform" />
<meta property="og:image" content="https://nextgraph.org/card.png"/>
<meta name="twitter:image" content="https://nextgraph.org/card-twitter.png"/>
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:description" content="Decentralized, encrypted and local-first platform and framework, towards the better internet we all deserve! Features a social network, shared documents, productivity tools, an app store, and more! You can use NextGraph for free, and it works online and offline. With NextGraph you own your data and software, having your privacy respected, while enjoying high-quality apps for your daily use. Try it now! Developers can build new web3.0 local-first apps with our open source framework, based on open standards, with CRDTs, E2EE, Semantic Web, RDF, SPARQL, JSON, Markdown, Svelte, React, JavaScript, Rust, etc... ActivityPub and Solid compatible." />
<meta name="description" content="Decentralized, encrypted and local-first platform and framework, towards the better internet we all deserve! Features a social network, shared documents, productivity tools, an app store, and more! You can use NextGraph for free, and it works online and offline. With NextGraph you own your data and software, having your privacy respected, while enjoying high-quality apps for your daily use. Try it now! Developers can build new web3.0 local-first apps with our open source framework, based on open standards, with CRDTs, E2EE, Semantic Web, RDF, SPARQL, JSON, Markdown, Svelte, React, JavaScript, Rust, etc... ActivityPub and Solid compatible.">
<link rel="stylesheet" href="/src/styles.css" />
<style>
.splashing {
height: 100vh;
width:100%;
display: flex;
justify-content: center;
align-items: center;
}
.noshow {
display: none !important;
}
.error-no-wasm-hidden {
display:none;
}
</style>
</head>
<body>
<div id="app"></div>
<div id="splash" class="splashing">
<div style="flex-direction: column; justify-content: center;
color:#4972a5;width:100%;text-align:left;
width:300px;
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;"
>
<svg
style="width:100px;height:100px;margin: 0 auto 20px ;display:flex;"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 225 225"
>
<g>
<circle
r="106.98013"
cy="112.90476"
cx="109.88096"
style="fill:#ffffff;stroke:none;stroke-width:0.268375" />
<path
d="M 98.343352,190.26108 C 80.403778,187.53354 65.011938,179.57839 52.608228,166.62327 38.602093,151.99448 31.178059,133.41381 31.178059,112.98841 c 0,-10.21889 1.700058,-19.44396 5.221234,-28.332119 4.28678,-10.820699 10.037295,-19.39063 18.535095,-27.62263 4.72982,-4.58187 6.60687,-6.10643 11.28099,-9.16256 11.89869,-7.779841 24.173884,-11.879991 38.095802,-12.724761 19.80437,-1.2017 39.11165,5.11306 54.60284,17.858751 1.50718,1.24006 2.72951,2.35934 2.71628,2.48729 -0.0132,0.12795 -3.85821,3.63443 -8.54442,7.79217 -4.6862,4.157729 -10.04724,8.96276 -11.91342,10.677819 -1.86617,1.715071 -3.54094,3.11831 -3.7217,3.11831 -0.18075,0 -1.39985,-0.745188 -2.70911,-1.655969 -7.53011,-5.23834 -15.99428,-7.82188 -25.62597,-7.82188 -12.731628,0 -23.249192,4.3379 -32.143882,13.257541 -6.39594,6.413868 -10.70387,14.555268 -12.50018,23.623578 -0.69099,3.48832 -0.68968,13.53072 0.002,17.00893 3.70508,18.62577 18.31886,33.10194 36.642322,36.29729 4.16439,0.72621 11.98099,0.71223 15.98975,-0.0286 14.03187,-2.59311 25.86047,-11.36806 32.26533,-23.93578 0.77379,-1.51834 1.26018,-2.88461 1.08086,-3.03616 -0.17934,-0.15156 -6.87448,-1.1779 -14.87813,-2.28078 -9.7795,-1.34758 -14.92353,-2.21379 -15.68471,-2.64117 -1.52067,-0.85379 -2.83611,-2.88806 -2.83611,-4.3859 0,-1.1732 2.02687,-15.86876 2.49085,-18.05962 0.29676,-1.40127 2.42559,-3.4934 3.84317,-3.77691 0.62227,-0.12445 8.82712,0.85555 18.28065,2.18348 9.43343,1.32511 17.26269,2.29453 17.39833,2.15427 0.13566,-0.14026 1.11808,-6.54833 2.18313,-14.24014 1.10778,-8.000208 2.20407,-14.60184 2.56177,-15.426229 0.34392,-0.792599 1.11019,-1.849131 1.70287,-2.34782 2.06321,-1.736079 3.1433,-1.785011 12.20439,-0.55291 9.63637,1.310309 10.70873,1.56224 12.28077,2.88503 1.64359,1.382979 2.2732,2.810909 2.25906,5.123309 -0.007,1.10173 -0.92172,8.29645 -2.03332,15.98826 -1.11158,7.69182 -1.97159,14.04091 -1.91113,14.1091 0.0605,0.0682 7.16644,1.11143 15.79109,2.31832 11.10566,1.55407 16.00827,2.38757 16.80223,2.85657 1.53015,0.90389 2.48023,2.64785 2.45017,4.49756 -0.0462,2.84349 -2.41252,18.12279 -2.97521,19.21089 -0.66164,1.27949 -2.60244,2.54696 -3.92109,2.56074 -0.51973,0.005 -7.87449,-0.95937 -16.34391,-2.144 -8.46944,-1.18464 -15.47588,-2.077 -15.56986,-1.98301 -0.094,0.094 -1.18792,7.34163 -2.43097,16.10589 -1.44004,10.15311 -2.49792,16.43621 -2.91556,17.31631 -0.72531,1.52848 -2.76261,3.06291 -4.53817,3.41802 -0.95688,0.19138 -10.90014,-0.92798 -13.59859,-1.53084 -0.5471,-0.12223 -1.89146,0.67252 -4.50941,2.66588 -11.2627,8.57562 -24.34195,13.90917 -38.35741,15.64164 -4.40038,0.54395 -15.72658,0.43298 -19.853658,-0.19451 z"
style="fill:#4972a5;fill-opacity:1;stroke:#4972a5;stroke-width:0.377976;stroke-opacity:1" />
</g>
</svg>
<div class="noshow" style="text-align:center;" id="app-loading">&nbsp;&nbsp;&nbsp;Loading ...</div>
<div id="error-no-wasm" style="padding-left:15px;" class="error-no-wasm-hidden">
Your browser is too old or is miss-configured.
Please try one of those options:<br/><br/>
- Upgrade to a newer version of this browser.<br/>
- Try with another browser software.<br/>
- <a href="https://nextgraph.org/download">install our native apps for
Linux, macOS, Windows desktops and laptops,
and iOS, Android mobiles.</a><br/><br/>
If you are using jshelter or another javascript protection mechanism,
please deactivate it as we need access to the WebWorker, JIT and WASM
features of your browser. If those features are disabled, please
enable them for this website.
</div>
<noscript style="display:grid;padding-left:15px;">
NextGraph cannot load as Javascript is currently deactivated.
You can use the CLI ngcli to access your documents in the terminal.
Or use the <a href="https://nextgraph.org/download">native apps
for Linux, macOS, Windows, Android, iOS.</a><br/>
Or setup an SSR static website generator with AtomicServer for javascript-less and
read-only access.
</noscript>
</div>
</div>
<script>
const supported = () => {
if (RegExp().hasIndices === undefined) {
console.error("no RegExp().hasIndices");
return false;
}
try {
if (Worker === undefined) {
console.error("no Worker");
return false;
}
new Worker(URL.createObjectURL(new Blob([';'], {type: 'application/javascript'})));
if (typeof WebAssembly === "object"
&& typeof WebAssembly.instantiate === "function") {
const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
if (module instanceof WebAssembly.Module)
return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
else {
console.log("no WebAssembly module");
}
}
} catch (e) {
console.error(e);
return false;
}
console.error("no WebAssembly");
return false;
};
if (check_supported && !supported()) {
window.document.getElementById("error-no-wasm").className="";
} else {
window.document.getElementById("app-loading").className="";
window.everything_ready = () => {
window.document.getElementById("splash").className="noshow";
window.document.getElementById("app").className="";
};
window.onload = () => {
window.ng_supported = true;
console.log("window loaded");
if (window.ng_spa_loaded) {
everything_ready();
}
};
}
</script>
<div id="app" class="noshow"></div>
<!-- # INSERT SCRIPT HERE -->
</body>
</html>

@ -1,34 +1,48 @@
{
"name": "nextgraph",
"name": "@ng-org/ng-app",
"private": true,
"version": "0.1.0",
"version": "0.1.2",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"build": "vite build",
"preview": "vite preview",
"tauri": "tauri",
"format": "prettier --write .",
"check": "svelte-check --tsconfig ./tsconfig.json"
"check": "svelte-check --tsconfig ./tsconfig.json",
"webdev": "cross-env NG_ENV_WEB=1 TAURI_DEBUG=1 NG_PUBLIC_DEV=1 vite",
"webbuild": "cross-env NG_ENV_WEB=1 NG_ENV_ONEFILE=1 vite build && node prepare-web-file.cjs",
"libwasm": "cd ../.. && cargo install cargo-run-script && cargo run-script libwasm && cd app/nextgraph",
"buildfrontdev": "pnpm -C ../../infra/ngnet/bootstrap builddev && pnpm -C ../../infra/ngnet/auth builddev && pnpm -C ../../infra/ngnet/redir builddev"
},
"dependencies": {
"@ark-ui/svelte": "^5.11.0",
"@dvcol/svelte-simple-router": "^2.7.2",
"@ng-org/lib-wasm": "workspace:*",
"@ng-org/ui-common": "workspace:*",
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-opener": "^2"
"@tauri-apps/plugin-opener": "^2",
"async-proxy": "^0.4.1"
},
"devDependencies": {
"@hazycora/vite-plugin-svelte-svg": "^2.4.3",
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.1.14",
"@tauri-apps/cli": "^2.8.4",
"@tsconfig/svelte": "^5.0.5",
"cross-env": "^10.1.0",
"daisyui": "^5.3.1",
"node-gzip": "^1.1.2",
"prettier": "^3.6.2",
"prettier-plugin-svelte": "^3.4.0",
"svelte": "^5.39.13",
"svelte-check": "^4.3.3",
"tailwindcss": "^4.1.14",
"typescript": "~5.6.2",
"vite": "^7.1.7"
"vite": "^7.1.7",
"vite-plugin-singlefile": "^2.3.0",
"vite-plugin-top-level-await": "^1.6.0",
"vite-plugin-wasm": "^3.5.0"
}
}

@ -0,0 +1,32 @@
const crypto = require('crypto');
const fs = require('fs');
const {gzip, } = require('node-gzip');
var algorithm = 'sha256'
, shasum = crypto.createHash(algorithm)
const sha_file = './dist-web/index.sha256';
const gzip_file = './dist-web/index.gzip';
var filename = './dist-web/index.html'
, s = fs.ReadStream(filename)
var bufs = [];
s.on('data', function(data) {
shasum.update(data)
bufs.push(data);
})
s.on('end', function() {
var hash = shasum.digest('hex')
console.log(hash + ' ' + filename)
fs.writeFileSync(sha_file, hash, 'utf8');
var buf = Buffer.concat(bufs);
gzip(buf).then((compressed) => {fs.writeFileSync(gzip_file, compressed);});
fs.rm(filename,()=>{});
})

@ -26,13 +26,19 @@ crate-type = ["staticlib", "cdylib", "rlib"]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = [] }
tauri = { version = "2", features = ["unstable"] }
tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_bare = "0.5.0"
serde_bytes = "0.11.7"
tauri-plugin-barcode-scanner = "2"
ng-repo = { path = "../../../engine/repo" }
ng-net = { path = "../../../engine/net" }
ng-wallet = { path = "../../../engine/wallet" }
nextgraph = { path = "../../../sdk/rust" }
oxrdf = { git = "https://git.nextgraph.org/NextGraph/oxigraph.git", branch="main", features = ["rdf-star", "oxsdatatypes"] }
async-std = { version = "1.12.0", features = ["attributes", "unstable"] }
sys-locale = { version = "0.3.1" }
zeroize = { version = "1.7.0", features = ["zeroize_derive"] }
ng-async-tungstenite = { git = "https://git.nextgraph.org/NextGraph/async-tungstenite.git", branch = "nextgraph", features = ["async-std-runtime", "async-native-tls"] }

File diff suppressed because it is too large Load Diff

@ -2,5 +2,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
nextgraph_lib::run()
nextgraph_lib::AppBuilder::new().run();
}

@ -1,11 +1,11 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "NextGraph",
"version": "0.1.0",
"version": "0.1.2",
"identifier": "org.nextgraph.app",
"build": {
"beforeDevCommand": "pnpm dev",
"devUrl": "http://localhost:5173",
"devUrl": "http://localhost:1420",
"beforeBuildCommand": "pnpm build",
"frontendDist": "../dist"
},
@ -14,8 +14,8 @@
"windows": [
{
"title": "NextGraph",
"width": 1024,
"height": 600
"width": 1280,
"height": 960
}
],
"security": {

@ -1,23 +1,33 @@
<!--
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
-->
<script lang="ts">
import ng from "@ng-org/ui-common/api";
import Logo from "./assets/logo.svg?component";
console.log(await ng.locales());
let info = await ng.client_info();
console.log(info.V0.details);
window.ng_spa_loaded = true;
if (window.ng_supported) {
console.log("READY");
window.everything_ready();
}
</script>
<div role="alert" class="alert alert-info">
<p class="text-3xl font-bold underline">Hello world!</p>
<div class="grid h-screen place-items-center">
<div style="height:144px;">
<Logo class="w-25"/>
</div>
</div>
<article class="prose lg:prose-xl">
<h1>Garlic bread with cheese: What the science tells us</h1>
<p>
For years parents have espoused the health benefits of eating garlic bread with cheese to
their children, with the food earning such an iconic status in our culture that kids will
often dress up as warm, cheesy loaf for Halloween.
</p>
<p>
But a recent study shows that the celebrated appetizer may be linked to a series of rabies
cases springing up around the country.
</p>
</article>
<style>
</style>

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 225 225"
>
<g>
<circle
r="106.98013"
cy="112.90476"
cx="109.88096"
style="fill:#ffffff;stroke:none;stroke-width:0.268375" />
<path
d="M 98.343352,190.26108 C 80.403778,187.53354 65.011938,179.57839 52.608228,166.62327 38.602093,151.99448 31.178059,133.41381 31.178059,112.98841 c 0,-10.21889 1.700058,-19.44396 5.221234,-28.332119 4.28678,-10.820699 10.037295,-19.39063 18.535095,-27.62263 4.72982,-4.58187 6.60687,-6.10643 11.28099,-9.16256 11.89869,-7.779841 24.173884,-11.879991 38.095802,-12.724761 19.80437,-1.2017 39.11165,5.11306 54.60284,17.858751 1.50718,1.24006 2.72951,2.35934 2.71628,2.48729 -0.0132,0.12795 -3.85821,3.63443 -8.54442,7.79217 -4.6862,4.157729 -10.04724,8.96276 -11.91342,10.677819 -1.86617,1.715071 -3.54094,3.11831 -3.7217,3.11831 -0.18075,0 -1.39985,-0.745188 -2.70911,-1.655969 -7.53011,-5.23834 -15.99428,-7.82188 -25.62597,-7.82188 -12.731628,0 -23.249192,4.3379 -32.143882,13.257541 -6.39594,6.413868 -10.70387,14.555268 -12.50018,23.623578 -0.69099,3.48832 -0.68968,13.53072 0.002,17.00893 3.70508,18.62577 18.31886,33.10194 36.642322,36.29729 4.16439,0.72621 11.98099,0.71223 15.98975,-0.0286 14.03187,-2.59311 25.86047,-11.36806 32.26533,-23.93578 0.77379,-1.51834 1.26018,-2.88461 1.08086,-3.03616 -0.17934,-0.15156 -6.87448,-1.1779 -14.87813,-2.28078 -9.7795,-1.34758 -14.92353,-2.21379 -15.68471,-2.64117 -1.52067,-0.85379 -2.83611,-2.88806 -2.83611,-4.3859 0,-1.1732 2.02687,-15.86876 2.49085,-18.05962 0.29676,-1.40127 2.42559,-3.4934 3.84317,-3.77691 0.62227,-0.12445 8.82712,0.85555 18.28065,2.18348 9.43343,1.32511 17.26269,2.29453 17.39833,2.15427 0.13566,-0.14026 1.11808,-6.54833 2.18313,-14.24014 1.10778,-8.000208 2.20407,-14.60184 2.56177,-15.426229 0.34392,-0.792599 1.11019,-1.849131 1.70287,-2.34782 2.06321,-1.736079 3.1433,-1.785011 12.20439,-0.55291 9.63637,1.310309 10.70873,1.56224 12.28077,2.88503 1.64359,1.382979 2.2732,2.810909 2.25906,5.123309 -0.007,1.10173 -0.92172,8.29645 -2.03332,15.98826 -1.11158,7.69182 -1.97159,14.04091 -1.91113,14.1091 0.0605,0.0682 7.16644,1.11143 15.79109,2.31832 11.10566,1.55407 16.00827,2.38757 16.80223,2.85657 1.53015,0.90389 2.48023,2.64785 2.45017,4.49756 -0.0462,2.84349 -2.41252,18.12279 -2.97521,19.21089 -0.66164,1.27949 -2.60244,2.54696 -3.92109,2.56074 -0.51973,0.005 -7.87449,-0.95937 -16.34391,-2.144 -8.46944,-1.18464 -15.47588,-2.077 -15.56986,-1.98301 -0.094,0.094 -1.18792,7.34163 -2.43097,16.10589 -1.44004,10.15311 -2.49792,16.43621 -2.91556,17.31631 -0.72531,1.52848 -2.76261,3.06291 -4.53817,3.41802 -0.95688,0.19138 -10.90014,-0.92798 -13.59859,-1.53084 -0.5471,-0.12223 -1.89146,0.67252 -4.50941,2.66588 -11.2627,8.57562 -24.34195,13.90917 -38.35741,15.64164 -4.40038,0.54395 -15.72658,0.43298 -19.853658,-0.19451 z"
style="fill:#4972a5;fill-opacity:1;stroke:#4972a5;stroke-width:0.377976;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

@ -0,0 +1,34 @@
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
import * as web_api from "@ng-org/lib-wasm";
import {init_api} from "@ng-org/ui-common/api";
init_api(web_api);
const NEW_VERSION = "0.1.2-alpha.1";
// cleaning old wallets :(
try {
let version = localStorage.getItem("ng_wallet_version");
if (!version || version != NEW_VERSION) {
localStorage.clear();
sessionStorage.clear();
localStorage.setItem("ng_wallet_version",NEW_VERSION)
}
}
catch (e) {
// it is ok to fail. it means access denied for local storage.
}
import { mount } from "svelte";
import App from "./App.svelte";
const app = mount(App, { target: document.getElementById("app") as Element });
export default app;

@ -1,3 +1,16 @@
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
import native_api from "./native-api";
import {init_api} from "@ng-org/ui-common/api";
init_api(native_api);
import { mount } from "svelte";
import App from "./App.svelte";

@ -0,0 +1,335 @@
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
import {createAsyncProxy} from "async-proxy";
import { Bowser } from "../../../sdk/js/lib-wasm/jsland/bowser.js";
import {version} from '../package.json';
import { Window } from '@tauri-apps/api/window';
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
const mapping = {
"privkey_to_string": ["privkey"],
"wallet_gen_shuffle_for_pazzle_opening": ["pazzle_length"],
"wallet_gen_shuffle_for_pin": [],
"wallet_open_with_pazzle": ["wallet","pazzle","pin"],
"wallet_open_with_mnemonic_words": ["wallet","mnemonic_words","pin"],
"wallet_open_with_mnemonic": ["wallet","mnemonic","pin"],
"wallet_was_opened": ["opened_wallet"],
"wallet_create": ["params"],
"wallet_read_file": ["file"],
"wallet_get_file": ["wallet_name"],
"wallet_import": ["encrypted_wallet","opened_wallet","in_memory"],
"wallet_export_rendezvous": ["session_id", "code"],
"wallet_export_get_qrcode": ["session_id", "size"],
"wallet_export_get_textcode": ["session_id"],
"wallet_import_rendezvous": ["size"],
"wallet_import_from_code": ["code"],
"wallet_close": ["wallet_name"],
"encode_create_account": ["payload"],
"session_start": ["wallet_name","user"],
"session_start_remote": ["wallet_name","user","peer_id"],
"session_stop": ["user_id"],
"get_wallets": [],
"open_window": ["url","label","title"],
"decode_invitation": ["invite"],
"user_connect": ["info","user_id","location"],
"user_disconnect": ["user_id"],
"discrete_update": ["session_id", "update", "heads", "crdt", "nuri"],
"app_request": ["request"],
"app_request_with_nuri_command": ["nuri", "command", "session_id", "payload"],
"sparql_query": ["session_id","sparql","base","nuri"],
"sparql_update": ["session_id","sparql","nuri"],
"test": [ ],
"get_device_name": [],
"doc_create": [ "session_id", "crdt", "class_name", "destination", "store_repo" ],
"doc_fetch_private_subscribe": [],
"doc_fetch_repo_subscribe": ["repo_o"],
"branch_history": ["session_id", "nuri"],
"file_save_to_downloads": ["session_id", "reference", "filename", "branch_nuri"],
"signature_status": ["session_id", "nuri"],
"signed_snapshot_request": ["session_id", "nuri"],
"signature_request": ["session_id", "nuri"],
"update_header": ["session_id","nuri","title","about"],
"fetch_header": ["session_id", "nuri"],
"retrieve_ng_bootstrap": ["location"],
}
let lastStreamId = 0;
const tauri_handler = {
async apply(target, path, caller, args) {
try {
if (path[0] === "open_window") {
let callback = args[3];
await invoke(path[0],{url:args[0],label:args[1],title:args[2]});
let unsub_register_accepted;
let unsub_register_error;
let unsub_register_close;
const unsub_register = function() {
if (unsub_register_accepted) unsub_register_accepted();
if (unsub_register_error) unsub_register_error();
if (unsub_register_close) unsub_register_close();
unsub_register_close = undefined;
unsub_register_error = undefined;
unsub_register_accepted = undefined;
};
unsub_register_accepted = await listen(
"accepted",
async (event) => {
unsub_register();
let reg_popup = Window.getByLabel("registration");
await reg_popup.close();
await (callback)("accepted",event.payload);
}
);
unsub_register_error = await listen("error", async (event) => {
unsub_register();
let reg_popup = Window.getByLabel("registration");
await reg_popup.close();
await (callback)("error",event.payload);
});
await new Promise((resolve) => setTimeout(resolve, 1000));
let reg_popup = Window.getByLabel("registration");
unsub_register_close = await reg_popup.onCloseRequested(async (event) => {
unsub_register_close = undefined;
unsub_register();
});
return unsub_register;
} else if (path[0] === "client_info") {
let from_rust = await invoke("client_info_rust",{});
let tauri_platform = import.meta.env.TAURI_ENV_PLATFORM;
let client_type;
switch (tauri_platform) {
case 'macos': client_type = "NativeMacOS";break;
case 'linux': client_type = "NativeLinux";break;
case 'windows': client_type = "NativeWin";break;
case 'android': client_type = "NativeAndroid";break;
case 'ios': client_type = "NativeIos";break;
}
let info = Bowser.parse(window.navigator.userAgent);
// info.os.type = import.meta.env.TAURI_ENV_PLATFORM_TYPE;
info.os.family = import.meta.env.TAURI_ENV_FAMILY;
info.os.version_tauri = import.meta.env.TAURI_ENV_PLATFORM_VERSION;
info.os.version_uname = from_rust.uname.version;
info.os.name_rust = from_rust.rust.os_name;
info.os.name_uname = from_rust.uname.os_name;
info.platform.arch = import.meta.env.TAURI_ENV_ARCH;
info.platform.debug = import.meta.env.TAURI_ENV_DEBUG;
info.platform.target = import.meta.env.TAURI_ENV_TARGET_TRIPLE;
info.platform.arch_uname = from_rust.uname.arch;
info.platform.bitness = from_rust.uname.bitness;
info.platform.codename = from_rust.uname.codename || undefined;
info.platform.edition = from_rust.uname.edition || undefined;
info.browser.ua = window.navigator.userAgent;
let res = {
// TODO: install timestamp
V0 : { client_type, details: JSON.stringify(info), version, timestamp_install:0, timestamp_updated:0 }
};
//console.log(info,res);
return res;
} else if (path[0] === "get_device_name") {
let tauri_platform = import.meta.env.TAURI_ENV_PLATFORM;
if (tauri_platform == 'android') return "Android Phone";
else if (tauri_platform == 'ios') return "iPhone";
else return await invoke(path[0],{});
} else if (path[0] === "locales") {
let from_rust = await invoke("locales",{});
let from_js = window.navigator.languages;
console.log(from_rust,from_js);
for (let lang of from_js) {
let split = lang.split("-");
if (split[1]) {
lang = split[0] + "-" + split[1].toUpperCase();
}
if (!from_rust.includes(lang)) { from_rust.push(lang);}
}
return from_rust;
} else if (path[0] === "disconnections_subscribe") {
let callback = args[0];
let unlisten = await Window.getCurrent().listen("disconnections", (event) => {
callback(event.payload).then(()=> {})
})
await invoke(path[0],{});
return () => {
unlisten();
}
} else if (path[0] === "user_connect") {
let arg = {};
args.map((el,ix) => arg[mapping[path[0]][ix]]=el)
let ret = await invoke(path[0],arg);
for (let e of Object.entries(ret)) {
e[1].since = new Date(e[1].since);
}
return ret;
}
else if (path[0] === "file_get") {
let stream_id = (lastStreamId += 1).toString();
//console.log("stream_id",stream_id);
//let session_id = args[0];
let callback = args[3];
let unlisten = await Window.getCurrent().listen(stream_id, async (event) => {
//console.log(event.payload);
if (event.payload.V0.FileBinary) {
event.payload.V0.FileBinary = Uint8Array.from(event.payload.V0.FileBinary);
}
let ret = callback(event.payload);
if (ret === true) {
await invoke("cancel_stream", {stream_id});
} else if (ret.then) {
ret.then(async (val)=> {
if (val === true) {
await invoke("cancel_stream", {stream_id});
}
});
}
})
try {
await invoke("file_get",{stream_id, session_id:args[0], reference: args[1], branch_nuri:args[2]});
} catch (e) {
unlisten();
await invoke("cancel_stream", {stream_id});
throw e;
}
return () => {
unlisten();
tauri.invoke("cancel_stream", {stream_id});
}
} else if (path[0] === "discrete_update") {
let arg = {};
args.map((el,ix) => arg[mapping[path[0]][ix]]=el)
arg.update = Array.from(new Uint8Array(arg.update));
return await invoke(path[0],arg)
} else if (path[0] === "app_request_stream") {
let stream_id = (lastStreamId += 1).toString();
//console.log("stream_id",stream_id);
//let session_id = args[0];
let request = args[0];
let callback = args[1];
let unlisten = await Window.getCurrent().listen(stream_id, async (event) => {
//console.log(event.payload);
if (event.payload.V0.FileBinary) {
event.payload.V0.FileBinary = Uint8Array.from(event.payload.V0.FileBinary);
}
if (event.payload.V0.State?.graph?.triples) {
let json_str = new TextDecoder().decode(Uint8Array.from(event.payload.V0.State.graph.triples));
event.payload.V0.State.graph.triples = JSON.parse(json_str);
} else if (event.payload.V0.Patch?.graph) {
let inserts_json_str = new TextDecoder().decode(Uint8Array.from(event.payload.V0.Patch.graph.inserts));
event.payload.V0.Patch.graph.inserts = JSON.parse(inserts_json_str);
let removes_json_str = new TextDecoder().decode(Uint8Array.from(event.payload.V0.Patch.graph.removes));
event.payload.V0.Patch.graph.removes = JSON.parse(removes_json_str);
}
if (event.payload.V0.State?.discrete) {
let crdt = Object.getOwnPropertyNames(event.payload.V0.State.discrete)[0];
event.payload.V0.State.discrete[crdt] = Uint8Array.from(event.payload.V0.State.discrete[crdt]);
} else if (event.payload.V0.Patch?.discrete) {
let crdt = Object.getOwnPropertyNames(event.payload.V0.Patch.discrete)[0];
event.payload.V0.Patch.discrete[crdt] = Uint8Array.from(event.payload.V0.Patch.discrete[crdt]);
}
let ret = callback(event.payload);
if (ret === true) {
await invoke("cancel_stream", {stream_id});
} else if (ret.then) {
ret.then(async (val)=> {
if (val === true) {
await invoke("cancel_stream", {stream_id});
}
});
}
})
try {
await invoke("app_request_stream",{stream_id, request});
} catch (e) {
unlisten();
await invoke("cancel_stream", {stream_id});
throw e;
}
return () => {
unlisten();
tauri.invoke("cancel_stream", {stream_id});
}
} else if (path[0] === "get_wallets") {
let res = await invoke(path[0],{});
if (res) for (let e of Object.entries(res)) {
e[1].wallet.V0.content.security_img = Uint8Array.from(e[1].wallet.V0.content.security_img);
}
return res || {};
} else if (path[0] === "wallet_import_from_code") {
let arg = {};
args.map((el,ix) => arg[mapping[path[0]][ix]]=el);
let res = await invoke(path[0],arg);
if (res) {
res.V0.content.security_img = Uint8Array.from(res.V0.content.security_img);
}
return res || {};
} else if (path[0] === "upload_chunk") {
let session_id = args[0];
let upload_id = args[1];
let chunk = args[2];
let nuri = args[3];
chunk = Array.from(new Uint8Array(chunk));
return await invoke(path[0],{session_id, upload_id, chunk, nuri})
} else if (path[0] === "wallet_create") {
let params = args[0];
params.result_with_wallet_file = false;
params.security_img = Array.from(new Uint8Array(params.security_img));
return await invoke(path[0],{params})
} else if (path[0] === "wallet_read_file") {
let file = args[0];
file = Array.from(new Uint8Array(file));
return await invoke(path[0],{file})
} else if (path[0] === "wallet_import") {
let encrypted_wallet = args[0];
encrypted_wallet.V0.content.security_img = Array.from(new Uint8Array(encrypted_wallet.V0.content.security_img));
return await invoke(path[0],{encrypted_wallet, opened_wallet:args[1], in_memory:args[2]})
} else if (path[0] && path[0].startsWith("get_local_bootstrap")) {
return false;
} else if (path[0] === "get_local_url") {
return false;
} else if (path[0] === "wallet_open_with_pazzle" || path[0] === "wallet_open_with_mnemonic_words" || path[0] === "wallet_open_with_mnemonic") {
let arg:any = {};
args.map((el,ix) => arg[mapping[path[0]][ix]]=el)
let img = Array.from(new Uint8Array(arg.wallet.V0.content.security_img));
let old_content = arg.wallet.V0.content;
arg.wallet = {V0:{id:arg.wallet.V0.id, sig:arg.wallet.V0.sig, content:{}}};
Object.assign(arg.wallet.V0.content,old_content);
arg.wallet.V0.content.security_img = img;
return await invoke(path[0],arg);
} else {
let arg = {};
args.map((el,ix) => arg[mapping[path[0]][ix]]=el)
return await invoke(path[0],arg)
}
} catch (e) {
let error;
try {
error = JSON.parse(e);
} catch (f) {
error = e;
}
throw error;
}
}
};
const tauri_api = createAsyncProxy({}, tauri_handler);
export default tauri_api;

@ -1,5 +1,10 @@
// svelte.config.js
export default {
compilerOptions: {
experimental: {
async: true
}
},
vitePlugin: {
//inspector: true
}

@ -20,5 +20,5 @@
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
}

@ -1,41 +1,167 @@
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "vite";
import { defineConfig, UserConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
import { viteSingleFile } from "vite-plugin-singlefile"
import svelteSVG from "@hazycora/vite-plugin-svelte-svg";
import wasm from "vite-plugin-wasm";
import topLevelAwait from "vite-plugin-top-level-await";
const host = process.env.TAURI_DEV_HOST;
// https://vite.dev/config/
export default defineConfig({
plugins: [tailwindcss(), svelte()],
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
//
// 1. prevent Vite from obscuring rust errors
clearScreen: false,
// 2. tauri expects a fixed port, fail if that port is not available
server: {
port: 5173,
strictPort: true,
host: host || false,
hmr: host
? {
protocol: "ws",
host,
port: 1421
}
: undefined,
watch: {
// 3. tell Vite to ignore watching `src-tauri`
ignored: ["**/src-tauri/**"]
export default defineConfig((): UserConfig => {
const worker_plugins = [];
const config = {
worker: {
format: 'es',
plugins : [
]
},
plugins: [
tailwindcss(),
svelte(),
svelteSVG({
svgoConfig: {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
// disable plugins
removeViewBox: false,
},
},
},
{
name: 'prefixIds',
}
],
}, // See https://github.com/svg/svgo#configuration
requireSuffix: true, // Set false to accept '.svg' without the '?component'
}),
],
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
//
// 1. prevent Vite from obscuring rust errors
clearScreen: false,
// 2. tauri expects a fixed port, fail if that port is not available
server: {
port: process.env.NG_ENV_WEB ? 1421 : 1420,
strictPort: true,
host: host || false,
hmr: host
? {
protocol: "ws",
host,
port: process.env.NG_ENV_WEB ? 5184 : 5183,
}
: undefined,
watch: {
// 3. tell Vite to ignore watching `src-tauri`
ignored: ["**/src-tauri/**"]
}
},
publicDir: process.env.NG_PUBLIC_DEV ? "public_dev" : false,
// Env variables starting with the item of `envPrefix` will be exposed in tauri's source code through `import.meta.env`.
envPrefix: ["VITE_", "TAURI_ENV_", "NG_ENV_"],
build: {
outDir: process.env.NG_ENV_WEB ? "dist-web" : "dist",
// Tauri uses Chromium on Windows and WebKit on macOS and Linux
target: process.env.TAURI_ENV_PLATFORM == "windows" ? "chrome105" : "safari13",
// don't minify for debug builds
minify: !process.env.TAURI_ENV_DEBUG ? "esbuild" : false,
// produce sourcemaps for debug builds
sourcemap: !!process.env.TAURI_ENV_DEBUG
}
},
// Env variables starting with the item of `envPrefix` will be exposed in tauri's source code through `import.meta.env`.
envPrefix: ["VITE_", "TAURI_ENV_*"],
build: {
// Tauri uses Chromium on Windows and WebKit on macOS and Linux
target: process.env.TAURI_ENV_PLATFORM == "windows" ? "chrome105" : "safari13",
// don't minify for debug builds
minify: !process.env.TAURI_ENV_DEBUG ? "esbuild" : false,
// produce sourcemaps for debug builds
sourcemap: !!process.env.TAURI_ENV_DEBUG
};
if (process.env.NG_ENV_WEB) {
if (process.env.NG_ENV_ONEFILE) {
config.plugins.push(viteSingleFile());
worker_plugins.push(viteSingleFile());
config.plugins.push(
{
name: 'move-script-body',
transformIndexHtml: {
order: 'post',
handler: function transform(html) {
let scriptTag = html.match(/<script type[^>]*>(.*?)<\/script[^>]*>/)[0]
//console.log("\n SCRIPT TAG", scriptTag, "\n")
html = html.replace(scriptTag, "")
html = html.replace("<!-- # INSERT SCRIPT HERE -->", scriptTag)
return html;
}
}
}
);
}
config.plugins.push(topLevelAwait());
config.plugins.push(wasm());
worker_plugins.push(topLevelAwait());
worker_plugins.push(wasm());
config.plugins.push(
{
name: 'inject-web-script',
transformIndexHtml: {
order: 'pre', // Tells Vite to run this before other processes
handler: function transform() {
return [
{
tag: "script",
children: "check_supported=true;",
injectTo: "head"
},
{
tag: "script",
attrs: {
"type": "module",
"src": "/src/main-web.ts",
"defer": true
},
injectTo: "head"
}]
}
}
}
);
} else {
config.plugins.push(
{
name: 'inject-native-script',
transformIndexHtml: {
order: 'pre', // Tells Vite to run this before other processes
handler: function transform() {
return [
{
tag: "script",
children: "check_supported=false;",
injectTo: "head"
},
{
tag: "script",
attrs: {
"type": "module",
"src": "/src/main.ts",
"defer": true
},
injectTo: "head"
}]
}
}
}
);
config.plugins.push(
{
name: 'make-script-defer',
transformIndexHtml: {
order: 'post',
handler: function transform(html) {
let new_html = html.replace("<script type","<script defer type");
return new_html;
}
}
}
);
}
config.worker.plugins = () => {return worker_plugins;};
return config;
});

@ -42,6 +42,8 @@ See [Build release binaries](../DEV.md#build-release-binaries) in the main READM
ngd --save-key -l 1440 --save-config
```
Note that for development, we use port 14400 while in production, port 1440 is used.
In the logs/output, you will see a link that you should open in your web browser. If there are many links, choose the one that starts with `http://localhost:`.
The computer you use to open the link should have direct access to the ngd server on localhost. In most of the cases, it will work, as you are running ngd on localhost. If you are running ngd in a docker container, then you need to give access to the container to the local network of the host by using `docker run --network="host"`. see more here https://docs.docker.com/network/drivers/host/
@ -73,9 +75,9 @@ ngcli --save-key --save-config -s 127.0.0.1,1440,<PEER_ID_OF_SERVER> -u <THE_PRI
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
`SPDX-License-Identifier: Apache-2.0 OR MIT`

@ -8,7 +8,7 @@
// according to those terms.
import "./app.postcss";
import "../../../common/src/styles.css";
import "../../../../app/ui-common/src/styles.css";
import App from "./App.svelte";
import { fromWritablePort } from 'remote-web-streams';
import web_api from "@ng-org/api-web";

@ -193,13 +193,13 @@ fn prepare_urls_from_private_addrs(addrs: &Vec<BindAddress>, port: u16) -> Vec<S
}
#[derive(RustEmbed)]
#[folder = "../../app/nextgraph/dist-file/"]
#[folder = "../../app/nextgraph/dist-web/"]
#[include = "*.sha256"]
#[include = "*.gzip"]
struct App;
#[derive(RustEmbed)]
#[folder = "../auth/dist/"]
#[folder = "./auth/dist/"]
#[include = "*.sha256"]
#[include = "*.gzip"]

@ -1,7 +1,7 @@
{
"name": "ng-account-web",
"private": true,
"version": "0.1.0",
"version": "0.1.2",
"type": "module",
"scripts": {
"dev": "cross-env NG_ACCOUNT_DOMAIN=example.com vite",

@ -1,7 +1,7 @@
{
"name": "@ng-org/net-redir",
"private": true,
"version": "0.1.0",
"version": "0.1.2",
"type": "module",
"scripts": {
"dev": "vite",

@ -2,7 +2,10 @@
"name": "ng-org",
"private": true,
"version": "0.1.2",
"scripts": {},
"scripts": {
"buildfront": "cargo run-script libwasm && pnpm -C ./app/nextgraph install && pnpm -C ./app/nextgraph webbuild && pnpm -C ./engine/broker/auth install && pnpm -C ./engine/broker/auth build",
"buildfrontdev": "pnpm -C ./engine/broker/auth builddev && pnpm -C ./infra/ngnet/bootstrap builddev && pnpm -C ./infra/ngnet/auth builddev && pnpm -C ./infra/ngnet/redir builddev"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [

File diff suppressed because it is too large Load Diff

@ -0,0 +1,86 @@
# JS SDK of NextGraph
## NextGraph
> NextGraph brings about the convergence of P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs.
>
> This open source ecosystem provides solutions for end-users (a platform) and software developers (a framework), wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers.
>
> More info here [https://nextgraph.org](https://nextgraph.org)
## WASM module
The [lib-wasm](../lib-wasm/README.md) crate contains the WASM module.
## Examples
- an example of web app using the vite bundler `example-webapp-vite`
- an example of React web app `app-react`
- an example of node-js app `app-node`
- `index.html` an example of vanilla JS usage of the SDK
## Support
Documentation can be found here [https://docs.nextgraph.org](https://docs.nextgraph.org)
And our community forum where you can ask questions is here [https://forum.nextgraph.org](https://forum.nextgraph.org)
## For developers
Read our [getting started guide](https://docs.nextgraph.org/en/getting-started/).
```
// for nodejs
npm i nextgraph
// or for browser
npm i nextgraphweb
```
## Publishing to npm
```
cargo run-script node
cd pkg-node
npm login --auth-type legacy
npm publish --auth-type legacy
```
### Example Plain JS web app (with Vite)
see [README here](example-webapp-vite/README.md)
### Example React web app
```
cd ../app-react
npm run dev
```
This URL will open automatically in browser : [http://localhost:8080](http://localhost:8080)
### Example NodeJS app
```
cd ../app-node
npm run start
```
### Contributions license
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you shall be dual licensed as below, without any
additional terms or conditions.
## License
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
`SPDX-License-Identifier: Apache-2.0 OR MIT`
---
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/assure) and the [NGI Zero Commons Fund](https://nlnet.nl/commonsfund/), both funds established by [NLnet](https://nlnet.nl/) Foundation with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreements No 957073 and No 101092990, respectively.

@ -1,10 +1,10 @@
# lib-wasm
# JS SDK of NextGraph
[![Apache 2.0 Licensed][license-image]][license-link]
[![MIT Licensed][license-image2]][license-link2]
[![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://forum.nextgraph.org)
JavaScript/WASM package containing the SDK of NextGraph
JavaScript package containing the SDK of NextGraph
## NextGraph
@ -25,7 +25,7 @@ And our community forum where you can ask questions is here [https://forum.nextg
Read our [getting started guide](https://docs.nextgraph.org/en/getting-started/).
```
npm i lib-wasm
npm i @ng-org/web
```
The API is divided in 4 parts:

@ -1,6 +1,4 @@
# lib-wasm
JS/WASM crate containing the SDK of NextGraph
# WASM module
## NextGraph
@ -10,33 +8,6 @@ JS/WASM crate containing the SDK of NextGraph
>
> More info here [https://nextgraph.org](https://nextgraph.org)
## JS/WASM module
This crate is composed of
- the npm package `lib-wasm` which is the SDK
- an example of web app using the vite bundler `example-webapp-vite`
- an example of React web app `app-react`
- an example of node-js app `app-node`
- `index.html` an example of vanilla JS usage of the SDK
## Support
Documentation can be found here [https://docs.nextgraph.org](https://docs.nextgraph.org)
And our community forum where you can ask questions is here [https://forum.nextgraph.org](https://forum.nextgraph.org)
## For developers
Read our [getting started guide](https://docs.nextgraph.org/en/getting-started/).
```
// for nodejs
npm i nextgraph
// or for browser
npm i nextgraphweb
```
## For contributors
First of all, run:
@ -45,8 +16,6 @@ First of all, run:
cargo install cargo-run-script
```
We recommend contributors to use the production build, as the creation and opening of wallets is very slow in the dev build.
Only use the dev build when debugging the sdk. see the next chapter for the production build.
Please note that the dev and prod builds share the same output folder, they thus override each other.
When building the app, be sure to have the production build of the SDK in the output folder.
@ -77,45 +46,15 @@ wasm-pack test --chrome --headless
```
cargo run-script app
tar --exclude .DS_Store -zcvf pkg.tar.gz pkg
cargo run-script node
cargo run-script web
```
## Publishing to npm
```
cargo run-script node
cd pkg-node
npm login --auth-type legacy
npm publish --auth-type legacy
```
### Example Plain JS web app (with Vite)
see [README here](example-webapp-vite/README.md)
### Example React web app
```
cd ../app-react
npm run dev
```
This URL will open automatically in browser : [http://localhost:8080](http://localhost:8080)
### Example NodeJS app
```
cd ../app-node
npm run start
```
### Contributions license
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you shall be dual licensed as below, without any
additional terms or conditions.s
additional terms or conditions.
## License

@ -7,39 +7,6 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
let ls;
let ss;
let no_local_storage; false;
(async () => {
try {
ls = localStorage;
ss = sessionStorage;
try {
let ret = await document.requestStorageAccess({ localStorage: true, sessionStorage: true });
ls = ret.localStorage;
ss = ret.sessionStorage;
console.log("REQUEST STORAGE ACCESS GRANTED by chrome");
}
catch(e) {
console.warn("requestStorageAccess of chrome failed. falling back to previous api", e)
try {
await document.requestStorageAccess();
localStorage;
console.log("REQUEST STORAGE ACCESS GRANTED");
} catch (e) {
console.error("REQUEST STORAGE ACCESS DENIED",e);
no_local_storage = true;
}
}
} catch (e) {
no_local_storage = true;
console.log("no access to localStorage")
}
})();
export function client_details() {
return window.navigator.userAgent;
}
@ -56,8 +23,7 @@ export function client_details2(obj,version) {
export function session_save(key,value) {
try {
ss.setItem(key, value);
sessionStorage.setItem(key, value);
} catch(e) {
console.error(e);
return convert_error(e.message);
@ -83,31 +49,24 @@ function convert_error(e) {
}
export function session_get(key) {
try {
return ss.getItem(key);
return sessionStorage.getItem(key);
} catch(e) {
console.error(e);
}
}
export function session_remove(key) {
try {
return ss.removeItem(key);
return sessionStorage.removeItem(key);
} catch(e) {
console.error(e);
}
}
export function local_save(key,value) {
try {
ls.setItem(key, value);
localStorage.setItem(key, value);
} catch(e) {
console.error(e);
return convert_error(e.message);
@ -116,21 +75,17 @@ export function local_save(key,value) {
export function storage_clear() {
try {
ls.clear();
ss.clear();
localStorage.clear();
sessionStorage.clear();
} catch(e) {
console.error(e);
}
}
export function local_get(key) {
try {
return ls.getItem(key);
return localStorage.getItem(key);
} catch(e) {
console.error(e);
}
}

@ -0,0 +1,181 @@
# This file is autogenerated by maturin v1.8.2
# To update, run
#
# maturin generate-ci github
#
name: CI
on:
push:
branches:
- main
- master
tags:
- '*'
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
linux:
runs-on: ${{ matrix.platform.runner }}
strategy:
matrix:
platform:
- runner: ubuntu-22.04
target: x86_64
- runner: ubuntu-22.04
target: x86
- runner: ubuntu-22.04
target: aarch64
- runner: ubuntu-22.04
target: armv7
- runner: ubuntu-22.04
target: s390x
- runner: ubuntu-22.04
target: ppc64le
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --out dist --find-interpreter
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
manylinux: auto
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-linux-${{ matrix.platform.target }}
path: dist
musllinux:
runs-on: ${{ matrix.platform.runner }}
strategy:
matrix:
platform:
- runner: ubuntu-22.04
target: x86_64
- runner: ubuntu-22.04
target: x86
- runner: ubuntu-22.04
target: aarch64
- runner: ubuntu-22.04
target: armv7
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --out dist --find-interpreter
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
manylinux: musllinux_1_2
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-musllinux-${{ matrix.platform.target }}
path: dist
windows:
runs-on: ${{ matrix.platform.runner }}
strategy:
matrix:
platform:
- runner: windows-latest
target: x64
- runner: windows-latest
target: x86
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
architecture: ${{ matrix.platform.target }}
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --out dist --find-interpreter
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-windows-${{ matrix.platform.target }}
path: dist
macos:
runs-on: ${{ matrix.platform.runner }}
strategy:
matrix:
platform:
- runner: macos-13
target: x86_64
- runner: macos-14
target: aarch64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --out dist --find-interpreter
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-macos-${{ matrix.platform.target }}
path: dist
sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
- name: Upload sdist
uses: actions/upload-artifact@v4
with:
name: wheels-sdist
path: dist
release:
name: Release
runs-on: ubuntu-latest
if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
needs: [linux, musllinux, windows, macos, sdist]
permissions:
# Use to sign the release artifacts
id-token: write
# Used to upload release artifacts
contents: write
# Used to generate artifact attestation
attestations: write
steps:
- uses: actions/download-artifact@v4
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v1
with:
subject-path: 'wheels-*/*'
- name: Publish to PyPI
if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: PyO3/maturin-action@v1
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with:
command: upload
args: --non-interactive --skip-existing wheels-*/*

@ -0,0 +1,72 @@
/target
.env/
# Byte-compiled / optimized / DLL files
__pycache__/
.pytest_cache/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
.venv/
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
include/
man/
venv/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
pip-selfcheck.json
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Django stuff:
*.log
*.pot
.DS_Store
# Sphinx documentation
docs/_build/
# PyCharm
.idea/
# VSCode
.vscode/
# Pyenv
.python-version

@ -0,0 +1,25 @@
[package]
name = "ng-sdk-python"
version.workspace = true
description = "NextGraph python package. Nextgraph is a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs"
edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
keywords = [ "crdt","e2ee","local-first","p2p","semantic-web" ]
documentation.workspace = true
rust-version.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "nextgraphpy"
crate-type = ["cdylib"]
[dependencies]
pyo3 = "0.23.3"
pyo3-async-runtimes = { version = "0.23", features = ["async-std-runtime"] }
pythonize = "0.23.0"
async-std = "1.12.0"
serde = { version = "1.0.142", features = ["derive"] }
nextgraph = { path = "../rust" }

@ -0,0 +1,63 @@
<p align="center">
<img src="https://git.nextgraph.org/NextGraph/nextgraph-rs/raw/branch/master/nextgraph/.static/header.png" alt="nextgraph-header" />
</p>
# nextgraphpy
![MSRV][rustc-image]
[![Apache 2.0 Licensed][license-image]][license-link]
[![MIT Licensed][license-image2]][license-link2]
[![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://forum.nextgraph.org)
[![PyPI - Version](https://img.shields.io/pypi/v/nextgraphpy)](https://pypi.org/project/nextgraphpy/)
Python package for NextGraph, implemented in Rust
This repository is in active development at [https://git.nextgraph.org/NextGraph/nextgraph-rs](https://git.nextgraph.org/NextGraph/nextgraph-rs), a Gitea instance. For bug reports, issues, merge requests, and in order to join the dev team, please visit the link above and create an account (you can do so with a github account). The [github repo](https://github.com/nextgraph-org/nextgraph-rs) is just a read-only mirror that does not accept issues.
## NextGraph
> NextGraph brings about the convergence of P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs.
>
> This open source ecosystem provides solutions for end-users (a platform) and software developers (a framework), wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers.
>
> More info here [https://nextgraph.org](https://nextgraph.org)
## Support
Documentation can be found here [https://docs.nextgraph.org](https://docs.nextgraph.org)
And our community forum where you can ask questions is here [https://forum.nextgraph.org](https://forum.nextgraph.org)
[![Mastodon](https://img.shields.io/badge/-MASTODON-%232B90D9?style=for-the-badge&logo=mastodon&logoColor=white)](https://fosstodon.org/@nextgraph)
## How to use NextGraph App & Platform
NextGraph is in alpha release!
You can try it online or by installing the apps. Please follow our [Getting started](https://docs.nextgraph.org/en/getting-started/) guide .
You can also subscribe to [our newsletter](https://list.nextgraph.org/subscription/form) to get updates, and support us with a [donation](https://nextgraph.org/donate/).
## NextGraph is also a Framework for App developers
Read our [getting started guide for developers](https://docs.nextgraph.org/en/framework/getting-started/).
## License
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
`SPDX-License-Identifier: Apache-2.0 OR MIT`
---
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/assure) and the [NGI Zero Commons Fund](https://nlnet.nl/commonsfund/), both funds established by [NLnet](https://nlnet.nl/) Foundation with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreements No 957073 and No 101092990, respectively.
[rustc-image]: https://img.shields.io/badge/rustc-1.81+-blue.svg
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg
[license-link]: https://git.nextgraph.org/NextGraph/nextgraph-rs/raw/branch/master/LICENSE-APACHE2
[license-image2]: https://img.shields.io/badge/license-MIT-blue.svg
[license-link2]: https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/LICENSE-MIT

@ -0,0 +1,17 @@
[build-system]
requires = ["maturin>=1.8,<2.0"]
build-backend = "maturin"
[project]
name = "nextgraphpy"
requires-python = ">=3.7.3"
description = "NextGraph brings about the convergence of P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs."
readme = "README.md"
classifiers = [
"Programming Language :: Rust",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
version = "0.1a1.dev4"
[tool.maturin]
features = ["pyo3/extension-module"]

@ -0,0 +1,167 @@
// Copyright (c) 2022-2025 Niko Bonnieure, Par le Peuple, NextGraph.org developers
// All rights reserved.
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;
use pythonize::{depythonize, pythonize};
use serde::{Deserialize, Serialize};
use std::fs::read;
#[allow(unused_imports)]
use ::nextgraph::local_broker::{
app_request, app_request_stream, doc_fetch_repo_subscribe, init_local_broker, session_start,
session_stop, user_connect, user_disconnect, wallet_close, wallet_create_v0, wallet_get,
wallet_get_file, wallet_import, wallet_read_file, wallet_was_opened, LocalBrokerConfig,
SessionConfig,
};
use ::nextgraph::net::app_protocol::*;
use ::nextgraph::net::types::BootstrapContentV0;
use ::nextgraph::repo::errors::NgError;
use ::nextgraph::repo::log::*;
use ::nextgraph::repo::types::{BranchCrdt, StoreRepo, PubKey};
use ::nextgraph::wallet::types::{CreateWalletV0, SessionInfo};
use ::nextgraph::wallet::{display_mnemonic, emojis::display_pazzle};
use async_std::stream::StreamExt;
#[pyfunction]
fn init_local_broker_in_memory() -> PyResult<()> {
Ok(())
}
struct PyNgError(NgError);
impl From<PyNgError> for PyErr {
fn from(e: PyNgError) -> PyErr {
let ioe: std::io::Error = e.0.into();
ioe.into()
}
}
impl From<NgError> for PyNgError {
fn from(e: NgError) -> PyNgError {
PyNgError(e)
}
}
/// Open the wallet with mnemonic and PIN, and returns the wallet_name and the SessionInfo
#[pyfunction]
fn wallet_open_with_mnemonic_words(
py: Python,
wallet_file_path: String,
mnemonic_words: Vec<String>,
pin: [u8; 4],
) -> PyResult<Bound<PyAny>> {
pyo3_async_runtimes::async_std::future_into_py(py, async move {
init_local_broker(Box::new(|| LocalBrokerConfig::InMemory)).await;
let wallet_file = read(wallet_file_path).expect("read wallet file");
let wallet = wallet_read_file(wallet_file)
.await
.map_err(|e| Into::<PyNgError>::into(e))?;
let opened_wallet = ::nextgraph::local_broker::wallet_open_with_mnemonic_words(
&wallet,
&mnemonic_words,
pin,
)
.map_err(|e| Into::<PyNgError>::into(e))?;
let user_id = opened_wallet.personal_identity();
let wallet_name = opened_wallet.name();
let _client = wallet_import(wallet.clone(), opened_wallet, true)
.await
.map_err(|e| Into::<PyNgError>::into(e))?;
let session = session_start(SessionConfig::new_in_memory(&user_id, &wallet_name))
.await
.map_err(|e| Into::<PyNgError>::into(e))?;
// let session = session_start(SessionConfig::new_remote(&user_id, &wallet_name, None)).await?;
let _status = user_connect(&user_id)
.await
.map_err(|e| Into::<PyNgError>::into(e))?;
let s = Python::with_gil(|py| pythonize(py, &session).unwrap().unbind());
Ok((wallet_name, s))
})
}
#[pyfunction]
#[pyo3(signature = (session_id, sparql, nuri=None))]
fn doc_sparql_update(
py: Python,
session_id: u64,
sparql: String,
nuri: Option<String>,
) -> PyResult<Bound<PyAny>> {
pyo3_async_runtimes::async_std::future_into_py(py, async move {
let res = ::nextgraph::local_broker::doc_sparql_update(session_id, sparql, nuri)
.await
.map_err(|e| PyTypeError::new_err(e))?;
Ok(res)
})
}
#[pyfunction]
fn disconnect_and_close<'a>(
py: Python<'a>,
user_id: Bound<'a, PyAny>,
wallet_name: String,
) -> PyResult<Bound<'a, PyAny>> {
let user_id: PubKey = depythonize(&user_id)?;
pyo3_async_runtimes::async_std::future_into_py(py, async move {
user_disconnect(&user_id)
.await
.map_err(|e| Into::<PyNgError>::into(e))?;
// stop the session
session_stop(&user_id)
.await
.map_err(|e| Into::<PyNgError>::into(e))?;
// closes the wallet
wallet_close(&wallet_name)
.await
.map_err(|e| Into::<PyNgError>::into(e))?;
Ok(())
})
}
#[pyfunction]
#[pyo3(signature = (session_id, crdt, class_name, destination="store".to_string(), store_type=None, store_repo=None))]
fn doc_create(
py: Python,
session_id: u64,
crdt: String,
class_name: String,
destination: String,
store_type: Option<String>,
store_repo: Option<String>,
) -> PyResult<Bound<PyAny>> {
pyo3_async_runtimes::async_std::future_into_py(py, async move {
Ok(nextgraph::local_broker::doc_create(session_id, crdt, class_name, destination, store_type, store_repo)
.await
.map_err(|e| Into::<PyNgError>::into(e))?
)
})
}
#[pymodule]
fn nextgraphpy(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(wallet_open_with_mnemonic_words, m)?)?;
m.add_function(wrap_pyfunction!(doc_sparql_update, m)?)?;
m.add_function(wrap_pyfunction!(disconnect_and_close, m)?)?;
m.add_function(wrap_pyfunction!(doc_create, m)?)?;
Ok(())
}

@ -0,0 +1,21 @@
import asyncio
from nextgraphpy import wallet_open_with_mnemonic_words, doc_create, doc_sparql_update, disconnect_and_close
async def main():
wallet_session = await wallet_open_with_mnemonic_words(
"/home/nn/Downloads/wallet-bCHhOmlelVtZ60jjGu7m-YtzF4TfD5WyErAMnEDOn-kA.ngw",
["mutual", "wife", "section", "actual", "spend", "illness", "save", "delay", "kiss", "crash", "baby", "degree" ],
[2, 3, 2, 3])
wallet_name = wallet_session[0]
session_info = wallet_session[1]
session_id = session_info["session_id"]
print(wallet_name)
print(session_info)
doc_id = await doc_create(session_id, "Graph", "data:graph", "store")
print(doc_id)
commits = await doc_sparql_update(session_id,
"INSERT DATA { <did:ng:_> <example:predicate> \"An example value22\". }", doc_id)
print(commits)
await disconnect_and_close(session_info["user"], wallet_name)
asyncio.run(main())

@ -27,7 +27,7 @@ This library is in active development at [https://git.nextgraph.org/NextGraph/ne
## Support
This crate has official documentation at [docs.rs](https://docs.rs/nextgraph/0.1.0/nextgraph/)
This crate has official documentation at [docs.rs](https://docs.rs/nextgraph/0.1.2/nextgraph/)
Documentation can be found here [https://docs.nextgraph.org](https://docs.nextgraph.org)
@ -44,7 +44,7 @@ A tokio-based version (as a feature) might be available in the future.
```toml
[dependencies]
nextgraph = "0.1.1-alpha.2"
nextgraph = "0.1.2"
async-std = "1.12.0"
```
@ -52,16 +52,16 @@ async-std = "1.12.0"
You can find some examples on how to use the library:
- [in_memory](https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/nextgraph/examples)
- [persistent](https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/nextgraph/examples)
- [in_memory](https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/nextgraph/examples)
- [persistent](https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/nextgraph/examples)
## License
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
`SPDX-License-Identifier: Apache-2.0 OR MIT`
@ -75,7 +75,6 @@ additional terms or conditions.
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/assure) and the [NGI Zero Commons Fund](https://nlnet.nl/commonsfund/), both funds established by [NLnet](https://nlnet.nl/) Foundation with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreements No 957073 and No 101092990, respectively.
[rustc-image]: https://img.shields.io/badge/rustc-1.81+-blue.svg
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg
[license-link]: https://git.nextgraph.org/NextGraph/nextgraph-rs/raw/branch/master/LICENSE-APACHE2

Loading…
Cancel
Save