@holochain/client 0.15.1 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,14 +13,11 @@ A JavaScript client for the Holochain Conductor API (works with browsers as well
13
13
 
14
14
  [Complete API reference](./docs/client.md)
15
15
 
16
- ## Compatibility
16
+ ## Installation
17
17
 
18
18
  **JS client v0.12.x** is compatible with **Holochain v0.1.x**.
19
19
 
20
- **JS client v0.14.x** is compatible with **Holochain v0.2.x**.
21
- *As target, ES2020 or higher is required when bundling for production*.
22
-
23
- ## Installation
20
+ **JS client v0.16.x** are compatible with **Holochain v0.2.x**.
24
21
 
25
22
  To install from NPM, run
26
23
  ```bash
@@ -33,7 +30,7 @@ npm install --save-exact @holochain/client
33
30
 
34
31
  ### Use AppAgentWebsocket with implicit zome call signing
35
32
  ```typescript
36
- import { AdminWebsocket, AppAgentWebsocket, CellType } from "@holochain/client";
33
+ import { ActionHash, AdminWebsocket, AppAgentWebsocket, CellType } from "@holochain/client";
37
34
 
38
35
  const adminWs = await AdminWebsocket.connect("ws://127.0.0.1:65000");
39
36
  const agent_key = await adminWs.generateAgentPubKey();
@@ -57,25 +54,15 @@ const appAgentWs = await AppAgentWebsocket.connect(
57
54
  installed_app_id
58
55
  );
59
56
 
60
- let signalCb;
61
- const signalReceived = new Promise<void>((resolve) => {
62
- signalCb = (signal) => {
63
- console.log("signal received", signal);
64
- // act on signal
65
- resolve();
66
- };
67
- });
68
-
69
- appAgentWs.on("signal", signalCb);
57
+ const zomeCallPayload: CallZomeRequest = {
58
+ cell_id,
59
+ zome_name: "zome_name",
60
+ fn_name: "create_entry",
61
+ provenance: agent_key,
62
+ payload: "some_content",
63
+ };
70
64
 
71
- // trigger an emit_signal
72
- await appAgentWs.callZome({
73
- role_name,
74
- zome_name: "zome",
75
- fn_name: "emitter",
76
- payload: null,
77
- });
78
- await signalReceived;
65
+ const response: ActionHash = await appAgentWs.callZome(zomeCallPayload, 30000);
79
66
 
80
67
  await appAgentWs.appWebsocket.client.close();
81
68
  await adminWs.client.close();
@@ -157,13 +144,6 @@ setSigningCredentials(cell_id, signingCredentials);
157
144
  localStorage.setItem(cellIdB64, JSON.stringify(signingCredentials));
158
145
  ```
159
146
 
160
- # Holochain Compatibility
161
-
162
- See [default.nix](./default.nix) for the Holochain version this package is compatible with.
163
-
164
- If updating the Holochain version included in holonix, please use `niv update` as explained in the
165
- [Holochain Installation Guide](https://developer.holochain.org/install-advanced/#upgrading-the-holochain-version).
166
-
167
147
  ## Running tests
168
148
 
169
149
  You need a version (`stable` toolchain) of Rust available.
@@ -382,12 +382,33 @@ export type NetworkSeed = string;
382
382
  * @public
383
383
  */
384
384
  export type InstallAppRequest = {
385
+ /**
386
+ * The agent to use when creating Cells for this App.
387
+ */
385
388
  agent_key: AgentPubKey;
389
+ /**
390
+ * The unique identifier for an installed app in this conductor.
391
+ * If not specified, it will be derived from the app name in the bundle manifest.
392
+ */
386
393
  installed_app_id?: InstalledAppId;
394
+ /**
395
+ * Include proof-of-membrane-membership data for cells that require it,
396
+ * keyed by the CellNick specified in the app bundle manifest.
397
+ */
387
398
  membrane_proofs: {
388
399
  [key: string]: MembraneProof;
389
400
  };
401
+ /**
402
+ * Optional global network seed override. If set will override the network seed value for all
403
+ * DNAs in the bundle.
404
+ */
390
405
  network_seed?: NetworkSeed;
406
+ /**
407
+ * Optional: If app installation fails due to genesis failure, normally the app will be immediately uninstalled.
408
+ * When this flag is set, the app is left installed with empty cells intact. This can be useful for
409
+ * using graft_records_onto_source_chain, or for diagnostics.
410
+ */
411
+ ignore_genesis_failure?: boolean;
391
412
  } & AppBundleSource;
392
413
  /**
393
414
  * @public
@@ -134,7 +134,7 @@ export class AdminWebsocket {
134
134
  * @returns The cap secret of the created capability.
135
135
  */
136
136
  grantSigningKey = async (cellId, functions, signingKey) => {
137
- const capSecret = randomCapSecret();
137
+ const capSecret = await randomCapSecret();
138
138
  await this.grantZomeCallCapability({
139
139
  cell_id: cellId,
140
140
  cap_grant: {
@@ -1,6 +1,6 @@
1
1
  import { hashZomeCall } from "@holochain/serialization";
2
2
  import { decode, encode } from "@msgpack/msgpack";
3
- import * as ed25519 from "@noble/ed25519";
3
+ import _sodium from "libsodium-wrappers";
4
4
  import Emittery from "emittery";
5
5
  import { getLauncherEnvironment, isLauncher, signZomeCallTauri, } from "../../environments/launcher.js";
6
6
  import { encodeHashToBase64 } from "../../utils/base64.js";
@@ -23,8 +23,9 @@ export class AppWebsocket extends Emittery {
23
23
  // Please retain until the upstream is fixed https://github.com/sindresorhus/emittery/issues/86.
24
24
  Object.getOwnPropertyNames(Emittery.prototype).forEach((name) => {
25
25
  const to_bind = this[name];
26
- if (typeof to_bind === 'function') {
27
- this[name] = to_bind.bind(this);
26
+ if (typeof to_bind === "function") {
27
+ this[name] =
28
+ to_bind.bind(this);
28
29
  }
29
30
  });
30
31
  this.client = client;
@@ -130,11 +131,15 @@ export const signZomeCall = async (request) => {
130
131
  fn_name: request.fn_name,
131
132
  provenance: signingCredentialsForCell.signingKey,
132
133
  payload: encode(request.payload),
133
- nonce: randomNonce(),
134
+ nonce: await randomNonce(),
134
135
  expires_at: getNonceExpiration(),
135
136
  };
136
137
  const hashedZomeCall = await hashZomeCall(unsignedZomeCallPayload);
137
- const signature = await ed25519.signAsync(hashedZomeCall, signingCredentialsForCell.keyPair.privateKey);
138
+ await _sodium.ready;
139
+ const sodium = _sodium;
140
+ const signature = sodium
141
+ .crypto_sign(hashedZomeCall, signingCredentialsForCell.keyPair.privateKey)
142
+ .subarray(0, sodium.crypto_sign_BYTES);
138
143
  const signedZomeCall = {
139
144
  ...unsignedZomeCallPayload,
140
145
  signature,
@@ -23,8 +23,9 @@ export class AppAgentWebsocket {
23
23
  // Please retain until the upstream is fixed https://github.com/sindresorhus/emittery/issues/86.
24
24
  Object.getOwnPropertyNames(Emittery.prototype).forEach((name) => {
25
25
  const to_bind = this.emitter[name];
26
- if (typeof to_bind === 'function') {
27
- this.emitter[name] = to_bind.bind(this.emitter);
26
+ if (typeof to_bind === "function") {
27
+ this.emitter[name] =
28
+ to_bind.bind(this.emitter);
28
29
  }
29
30
  });
30
31
  const env = getLauncherEnvironment();
@@ -1,16 +1,10 @@
1
- import { CapSecret } from "../hdk/capabilities.js";
2
- import { AgentPubKey, CellId } from "../types.js";
1
+ import { type KeyPair } from "libsodium-wrappers";
2
+ import type { CapSecret } from "../hdk/capabilities.js";
3
+ import type { AgentPubKey, CellId } from "../types.js";
3
4
  /**
4
5
  * @public
5
6
  */
6
7
  export type Nonce256Bit = Uint8Array;
7
- /**
8
- * @public
9
- */
10
- export interface KeyPair {
11
- privateKey: Uint8Array;
12
- publicKey: Uint8Array;
13
- }
14
8
  /**
15
9
  * @public
16
10
  */
@@ -39,26 +33,25 @@ export declare const setSigningCredentials: (cellId: CellId, credentials: Signin
39
33
  /**
40
34
  * Generates a key pair for signing zome calls.
41
35
  *
36
+ * @param agentPubKey - The agent pub key to take 4 last bytes (= DHT location)
37
+ * from (optional).
42
38
  * @returns The signing key pair and an agent pub key based on the public key.
43
39
  *
44
40
  * @public
45
41
  */
46
- export declare const generateSigningKeyPair: () => Promise<[
47
- KeyPair,
48
- AgentPubKey
49
- ]>;
42
+ export declare const generateSigningKeyPair: (agentPubKey?: AgentPubKey) => Promise<[KeyPair, AgentPubKey]>;
50
43
  /**
51
44
  * @public
52
45
  */
53
- export declare const randomCapSecret: () => CapSecret;
46
+ export declare const randomCapSecret: () => Promise<CapSecret>;
54
47
  /**
55
48
  * @public
56
49
  */
57
- export declare const randomNonce: () => Nonce256Bit;
50
+ export declare const randomNonce: () => Promise<Nonce256Bit>;
58
51
  /**
59
52
  * @public
60
53
  */
61
- export declare const randomByteArray: (length: number) => Uint8Array;
54
+ export declare const randomByteArray: (length: number) => Promise<Uint8Array>;
62
55
  /**
63
56
  * @public
64
57
  */
@@ -1,8 +1,5 @@
1
- import * as ed25519 from "@noble/ed25519";
1
+ import _sodium from "libsodium-wrappers";
2
2
  import { encodeHashToBase64 } from "../utils/base64.js";
3
- if (!globalThis.crypto) {
4
- import("node:crypto").then((webcrypto) => (globalThis.crypto = webcrypto));
5
- }
6
3
  const signingCredentials = new Map();
7
4
  /**
8
5
  * Get credentials for signing zome calls.
@@ -30,29 +27,39 @@ export const setSigningCredentials = (cellId, credentials) => {
30
27
  /**
31
28
  * Generates a key pair for signing zome calls.
32
29
  *
30
+ * @param agentPubKey - The agent pub key to take 4 last bytes (= DHT location)
31
+ * from (optional).
33
32
  * @returns The signing key pair and an agent pub key based on the public key.
34
33
  *
35
34
  * @public
36
35
  */
37
- export const generateSigningKeyPair = async () => {
38
- const privateKey = ed25519.utils.randomPrivateKey();
39
- const publicKey = await ed25519.getPublicKeyAsync(privateKey);
40
- const keyPair = { privateKey, publicKey };
41
- const signingKey = new Uint8Array([132, 32, 36].concat(...publicKey).concat(...[0, 0, 0, 0]));
36
+ export const generateSigningKeyPair = async (agentPubKey) => {
37
+ await _sodium.ready;
38
+ const sodium = _sodium;
39
+ const keyPair = sodium.crypto_sign_keypair();
40
+ const locationBytes = agentPubKey ? agentPubKey.subarray(35) : [0, 0, 0, 0];
41
+ const signingKey = new Uint8Array([132, 32, 36].concat(...keyPair.publicKey).concat(...locationBytes));
42
42
  return [keyPair, signingKey];
43
43
  };
44
44
  /**
45
45
  * @public
46
46
  */
47
- export const randomCapSecret = () => randomByteArray(64);
47
+ export const randomCapSecret = async () => randomByteArray(64);
48
48
  /**
49
49
  * @public
50
50
  */
51
- export const randomNonce = () => randomByteArray(32);
51
+ export const randomNonce = async () => randomByteArray(32);
52
52
  /**
53
53
  * @public
54
54
  */
55
- export const randomByteArray = (length) => globalThis.crypto.getRandomValues(new Uint8Array(length));
55
+ export const randomByteArray = async (length) => {
56
+ if (globalThis.crypto && "getRandomValues" in globalThis.crypto) {
57
+ return globalThis.crypto.getRandomValues(new Uint8Array(length));
58
+ }
59
+ await _sodium.ready;
60
+ const sodium = _sodium;
61
+ return sodium.randombytes_buf(length);
62
+ };
56
63
  /**
57
64
  * @public
58
65
  */
@@ -11,7 +11,7 @@ export const signZomeCallTauri = async (request) => {
11
11
  zome_name: request.zome_name,
12
12
  fn_name: request.fn_name,
13
13
  payload: Array.from(encode(request.payload)),
14
- nonce: Array.from(randomNonce()),
14
+ nonce: Array.from(await randomNonce()),
15
15
  expires_at: getNonceExpiration(),
16
16
  };
17
17
  const signedZomeCallTauri = await invoke("sign_zome_call", { zomeCallUnsigned });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holochain/client",
3
- "version": "0.15.1",
3
+ "version": "0.16.1",
4
4
  "description": "A JavaScript client for the Holochain Conductor API",
5
5
  "author": "Holochain Foundation <info@holochain.org> (http://holochain.org)",
6
6
  "license": "CAL-1.0",
@@ -46,6 +46,7 @@
46
46
  "emittery": "^1.0.1",
47
47
  "isomorphic-ws": "^5.0.0",
48
48
  "js-base64": "^3.7.3",
49
+ "libsodium-wrappers": "^0.7.11",
49
50
  "lodash-es": "^4.17.21",
50
51
  "ws": "^8.13.0"
51
52
  },
@@ -53,17 +54,18 @@
53
54
  "@microsoft/api-documenter": "^7.21.7",
54
55
  "@microsoft/api-extractor": "^7.34.4",
55
56
  "@types/js-yaml": "^3.12.7",
57
+ "@types/libsodium-wrappers": "^0.7.10",
56
58
  "@types/lodash-es": "^4.17.6",
57
59
  "@types/tape": "^4.13.2",
58
60
  "@types/ws": "^8.5.3",
59
- "@typescript-eslint/eslint-plugin": "^5.27.0",
60
- "@typescript-eslint/parser": "^5.27.0",
61
- "eslint": "^8.16.0",
62
- "eslint-config-prettier": "^8.5.0",
63
- "eslint-plugin-prettier": "^4.0.0",
64
- "eslint-plugin-tsdoc": "^0.2.16",
61
+ "@typescript-eslint/eslint-plugin": "^5.62.0",
62
+ "@typescript-eslint/parser": "^5.62.0",
63
+ "eslint": "^8.46.0",
64
+ "eslint-config-prettier": "^8.10.0",
65
+ "eslint-plugin-prettier": "^4.2.1",
66
+ "eslint-plugin-tsdoc": "^0.2.17",
65
67
  "js-yaml": "^3.14.1",
66
- "prettier": "^2.6.2",
68
+ "prettier": "^2.8.8",
67
69
  "rimraf": "^3.0.2",
68
70
  "tape": "^5.5.3",
69
71
  "ts-node": "^10.9.1",