diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index eabbc178..205809b4 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -67,6 +67,12 @@ jobs: - name: Run tests run: nix develop -c $SHELL -c "npm t" + - name: Run doc test of app websocket + run: nix develop -c $SHELL -c "./doc-test-app-ws.sh" + + - name: Run doc test of signal + run: nix develop -c $SHELL -c "./doc-test-signal.sh" + - name: Setup tmate session if a previous step failed if: ${{ failure() }} uses: mxschmitt/action-tmate@v3 diff --git a/README.md b/README.md index 1941b2aa..6757da63 100644 --- a/README.md +++ b/README.md @@ -30,64 +30,92 @@ npm install --save-exact @holochain/client ## Sample usage -### Use AppAgentWebsocket with implicit zome call signing +### Use AppWebsocket with implicit zome call signing ```typescript -import { ActionHash, AdminWebsocket, AppAgentWebsocket, CellType } from "@holochain/client"; - -const adminWs = await AdminWebsocket.connect({url: "ws://127.0.0.1:65000"}); +import { + AdminWebsocket, + AppWebsocket, + CellType, + type ActionHash, + type CallZomeRequest, +} from "./lib/index.js"; + +const adminWs = await AdminWebsocket.connect({ + url: new URL("ws://127.0.0.1:65000"), + wsClientOptions: { origin: "my-happ" }, +}); const agent_key = await adminWs.generateAgentPubKey(); -const role_name = "role"; +const role_name = "foo"; const installed_app_id = "test-app"; const appInfo = await adminWs.installApp({ agent_key, - path: "path/to/happ/file", + path: "./test/e2e/fixture/test.happ", installed_app_id, membrane_proofs: {}, }); await adminWs.enableApp({ installed_app_id }); if (!(CellType.Provisioned in appInfo.cell_info[role_name][0])) { - process.exit(); + throw new Error(`No cell found under role name ${role_name}`); } const { cell_id } = appInfo.cell_info[role_name][0][CellType.Provisioned]; await adminWs.authorizeSigningCredentials(cell_id); -await adminWs.attachAppInterface({ port: 65001 }); -const appAgentWs = await AppAgentWebsocket.connect(installed_app_id, {url: "ws://127.0.0.1:65001"}); +await adminWs.attachAppInterface({ port: 65001, allowed_origins: "my-happ" }); +const issuedToken = await adminWs.issueAppAuthenticationToken({ + installed_app_id, +}); +const appWs = await AppWebsocket.connect({ + url: new URL("ws://127.0.0.1:65001"), + token: issuedToken.token, + wsClientOptions: { origin: "my-happ" }, +}); const zomeCallPayload: CallZomeRequest = { cell_id, - zome_name: "zome_name", - fn_name: "create_entry", + zome_name: "foo", + fn_name: "foo", provenance: agent_key, - payload: "some_content", + payload: null, }; -const response: ActionHash = await appAgentWs.callZome(zomeCallPayload, 30000); +const response: ActionHash = await appWs.callZome(zomeCallPayload, 30000); +console.log("zome call response is", response); -await appAgentWs.appWebsocket.client.close(); +await appWs.client.close(); await adminWs.client.close(); ``` -### Use AppWebsocket with implicit zome call signing +### Subscribe to signals ```typescript import { AdminWebsocket, AppWebsocket, CellType } from "@holochain/client"; -const adminWs = await AdminWebsocket.connect({url: "ws://127.0.0.1:65000"}); +const adminWs = await AdminWebsocket.connect({ + url: new URL("ws://127.0.0.1:65000"), + wsClientOptions: { origin: "my-happ" }, +}); const agent_key = await adminWs.generateAgentPubKey(); +const role_name = "foo"; const installed_app_id = "test-app"; const appInfo = await adminWs.installApp({ agent_key, - path: "path/to/happ/file", + path: "./test/e2e/fixture/test.happ", installed_app_id, membrane_proofs: {}, }); await adminWs.enableApp({ installed_app_id }); -if (!(CellType.Provisioned in appInfo.cell_info["role"][0])) { - process.exit(); +if (!(CellType.Provisioned in appInfo.cell_info[role_name][0])) { + throw new Error(`No cell found under role name ${role_name}`); } -const { cell_id } = appInfo.cell_info["role"][0][CellType.Provisioned]; +const { cell_id } = appInfo.cell_info[role_name][0][CellType.Provisioned]; await adminWs.authorizeSigningCredentials(cell_id); -await adminWs.attachAppInterface({ port: 65001 }); -const appWs = await AppWebsocket.connect({url: "ws://127.0.0.1:65001"}); +await adminWs.attachAppInterface({ port: 65001, allowed_origins: "my-happ" }); +const issuedToken = await adminWs.issueAppAuthenticationToken({ + installed_app_id, +}); +const appWs = await AppWebsocket.connect({ + url: new URL("ws://127.0.0.1:65001"), + token: issuedToken.token, + wsClientOptions: { origin: "my-happ" }, +}); let signalCb; const signalReceived = new Promise((resolve) => { @@ -103,7 +131,7 @@ appWs.on("signal", signalCb); // trigger an emit_signal await appWs.callZome({ cell_id, - zome_name: "zome", + zome_name: "foo", fn_name: "emitter", provenance: agent_key, payload: null, @@ -165,7 +193,7 @@ Holochain is an open source project. We welcome all sorts of participation and [![License: CAL 1.0](https://img.shields.io/badge/License-CAL%201.0-blue.svg)](https://github.com/holochain/cryptographic-autonomy-license) -Copyright (C) 2020-2023, Holochain Foundation +Copyright (C) 2020-2024, Holochain Foundation This program is free software: you can redistribute it and/or modify it under the terms of the license provided in the LICENSE file (CAL-1.0). This program is distributed in the hope that it will be useful, diff --git a/doc-test-app-ws.sh b/doc-test-app-ws.sh new file mode 100755 index 00000000..61cb0177 --- /dev/null +++ b/doc-test-app-ws.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -xe + +hc s clean +echo "" | hc s --piped create +echo "" | hc s --piped -f=65000 run & +HC_ID=$! +echo "HC_ID is $HC_ID" +sleep 5 + +set +e + +npm run build +npx tsx doc-test-app-ws.ts + +pkill -15 -P $HC_ID diff --git a/doc-test-app-ws.ts b/doc-test-app-ws.ts new file mode 100644 index 00000000..a7c01ae5 --- /dev/null +++ b/doc-test-app-ws.ts @@ -0,0 +1,50 @@ +import { + AdminWebsocket, + AppWebsocket, + CellType, + type ActionHash, + type CallZomeRequest, +} from "./lib/index.js"; + +const adminWs = await AdminWebsocket.connect({ + url: new URL("ws://127.0.0.1:65000"), + wsClientOptions: { origin: "my-happ" }, +}); +const agent_key = await adminWs.generateAgentPubKey(); +const role_name = "foo"; +const installed_app_id = "test-app"; +const appInfo = await adminWs.installApp({ + agent_key, + path: "./test/e2e/fixture/test.happ", + installed_app_id, + membrane_proofs: {}, +}); +await adminWs.enableApp({ installed_app_id }); +if (!(CellType.Provisioned in appInfo.cell_info[role_name][0])) { + throw new Error(`No cell found under role name ${role_name}`); +} +const { cell_id } = appInfo.cell_info[role_name][0][CellType.Provisioned]; +await adminWs.authorizeSigningCredentials(cell_id); +await adminWs.attachAppInterface({ port: 65001, allowed_origins: "my-happ" }); +const issuedToken = await adminWs.issueAppAuthenticationToken({ + installed_app_id, +}); +const appWs = await AppWebsocket.connect({ + url: new URL("ws://127.0.0.1:65001"), + token: issuedToken.token, + wsClientOptions: { origin: "my-happ" }, +}); + +const zomeCallPayload: CallZomeRequest = { + cell_id, + zome_name: "foo", + fn_name: "foo", + provenance: agent_key, + payload: null, +}; + +const response: ActionHash = await appWs.callZome(zomeCallPayload, 30000); +console.log("zome call response is", response); + +await appWs.client.close(); +await adminWs.client.close(); diff --git a/doc-test-signal.sh b/doc-test-signal.sh new file mode 100755 index 00000000..1dbff1d5 --- /dev/null +++ b/doc-test-signal.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -xe + +hc s clean +echo "" | hc s --piped create +echo "" | hc s --piped -f=65000 run & +HC_ID=$! +echo "HC_ID is $HC_ID" +sleep 5 + +set +e + +npm run build +npx tsx doc-test-signal.ts + +pkill -15 -P $HC_ID diff --git a/doc-test-signal.ts b/doc-test-signal.ts new file mode 100644 index 00000000..bdfa8f1f --- /dev/null +++ b/doc-test-signal.ts @@ -0,0 +1,54 @@ +import { AdminWebsocket, AppWebsocket, CellType } from "./lib/index.js"; + +const adminWs = await AdminWebsocket.connect({ + url: new URL("ws://127.0.0.1:65000"), + wsClientOptions: { origin: "my-happ" }, +}); +const agent_key = await adminWs.generateAgentPubKey(); +const role_name = "foo"; +const installed_app_id = "test-app"; +const appInfo = await adminWs.installApp({ + agent_key, + path: "./test/e2e/fixture/test.happ", + installed_app_id, + membrane_proofs: {}, +}); +await adminWs.enableApp({ installed_app_id }); +if (!(CellType.Provisioned in appInfo.cell_info[role_name][0])) { + throw new Error(`No cell found under role name ${role_name}`); +} +const { cell_id } = appInfo.cell_info[role_name][0][CellType.Provisioned]; +await adminWs.authorizeSigningCredentials(cell_id); +await adminWs.attachAppInterface({ port: 65001, allowed_origins: "my-happ" }); +const issuedToken = await adminWs.issueAppAuthenticationToken({ + installed_app_id, +}); +const appWs = await AppWebsocket.connect({ + url: new URL("ws://127.0.0.1:65001"), + token: issuedToken.token, + wsClientOptions: { origin: "my-happ" }, +}); + +let signalCb; +const signalReceived = new Promise((resolve) => { + signalCb = (signal) => { + console.log("signal received", signal); + // act on signal + resolve(); + }; +}); + +appWs.on("signal", signalCb); + +// trigger an emit_signal +await appWs.callZome({ + cell_id, + zome_name: "foo", + fn_name: "emitter", + provenance: agent_key, + payload: null, +}); +await signalReceived; + +await appWs.client.close(); +await adminWs.client.close(); diff --git a/flake.lock b/flake.lock index ae942a52..71a7a4e5 100644 --- a/flake.lock +++ b/flake.lock @@ -141,16 +141,16 @@ "holochain": { "flake": false, "locked": { - "lastModified": 1714578487, - "narHash": "sha256-R0nmeZEEkHBCPmLiuWpx54qjGrrbay4b0QxxIJXsn2o=", + "lastModified": 1715129891, + "narHash": "sha256-M+AoE56LNvtoP7EP+XBI9GaMEKoJ9aeslGHw3WKPB0I=", "owner": "holochain", "repo": "holochain", - "rev": "f64ad12ccb5e3c872f5588a32437f03fef0b154b", + "rev": "6e9dbbedc4879cf344c5fc9a324e5ce025048405", "type": "github" }, "original": { "owner": "holochain", - "ref": "holochain-0.4.0-dev.1", + "ref": "holochain-0.4.0-dev.2", "repo": "holochain", "type": "github" } @@ -190,11 +190,11 @@ ] }, "locked": { - "lastModified": 1714667236, - "narHash": "sha256-9a513FOx85vQCtlTZ2l5PXhnonrsZ17kFPVxB3VNrrM=", + "lastModified": 1715606107, + "narHash": "sha256-31LdKF0b93GQOKzKyG8bGbfisqR8Hw5Y3EFT/su7DU0=", "owner": "holochain", "repo": "holochain", - "rev": "81758593fca175978fb1d61ee61f39cf968907f5", + "rev": "c745c93471d697cbbe2f1f3478a0a8dacbf00ffc", "type": "github" }, "original": { @@ -223,11 +223,11 @@ "launcher": { "flake": false, "locked": { - "lastModified": 1714396970, - "narHash": "sha256-I/Vpxtg8cwhrrD5JugEgE4Qk8fZR6VewGm5FX69vbm0=", + "lastModified": 1715106263, + "narHash": "sha256-a7iQ8pKGz6fghJrtXq0Xamp57GE8Hd3w5YQASzz5Wlk=", "owner": "holochain", "repo": "launcher", - "rev": "b96d5aa790bf0da0a8f0c44741276f7f9c4b6b41", + "rev": "92bd39e1c66912d61c35c4725d7b106959888670", "type": "github" }, "original": { @@ -254,11 +254,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1714253743, - "narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=", + "lastModified": 1715447595, + "narHash": "sha256-VsVAUQOj/cS1LCOmMjAGeRksXIAdPnFIjCQ0XLkCsT0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994", + "rev": "062ca2a9370a27a35c524dc82d540e6e9824b652", "type": "github" }, "original": { @@ -332,11 +332,11 @@ ] }, "locked": { - "lastModified": 1714616033, - "narHash": "sha256-JcWAjIDl3h0bE/pII0emeHwokTeBl+SWrzwrjoRu7a0=", + "lastModified": 1715566659, + "narHash": "sha256-OpI0TnN+uE0vvxjPStlTzf5RTohIXVSMwrP9NEgMtaY=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "3e416d5067ba31ff8ac31eeb763e4388bdf45089", + "rev": "6c465248316cd31502c82f81f1a3acf2d621b01c", "type": "github" }, "original": { @@ -348,11 +348,11 @@ "scaffolding": { "flake": false, "locked": { - "lastModified": 1713363855, - "narHash": "sha256-Y9KsDAjlZZab07NL7pI1izxLOYT4BWYTx1h9DilW8Fk=", + "lastModified": 1715149384, + "narHash": "sha256-b8pfU/yt7zPV1BxkulfOB7NtPcNU42r6mUjDwI9lCAc=", "owner": "holochain", "repo": "scaffolding", - "rev": "9ac485d52122b92bd2988a8fea1a8e4d9a18c3a1", + "rev": "660696736f37fc2c778d429e12d1e45014fecfb9", "type": "github" }, "original": { @@ -386,11 +386,11 @@ }, "locked": { "dir": "versions/weekly", - "lastModified": 1714667236, - "narHash": "sha256-9a513FOx85vQCtlTZ2l5PXhnonrsZ17kFPVxB3VNrrM=", + "lastModified": 1715606107, + "narHash": "sha256-31LdKF0b93GQOKzKyG8bGbfisqR8Hw5Y3EFT/su7DU0=", "owner": "holochain", "repo": "holochain", - "rev": "81758593fca175978fb1d61ee61f39cf968907f5", + "rev": "c745c93471d697cbbe2f1f3478a0a8dacbf00ffc", "type": "github" }, "original": {