{"bugs":{"url":"https://github.com/streamr-dev/network/issues"},"dist":{"shasum":"155c0ff5b040cfce15aecd24707fc82a3d753d4e","tarball":"https://registry.npmjs.org/streamr-client/-/streamr-client-7.4.0-beta.1.tgz","fileCount":282,"integrity":"sha512-ptvOQhyU/taVO93FxdvnwbHlaNoedXOqeXupsHkX2o0ssIl4HamIYetk52Y+/eSMLU9/0gCJn3AjLhabE5yvVw==","signatures":[{"sig":"MEQCIEhEGKZynh9UAOJCVzjKlGU5urN48Z979jFFQzZ4KXJzAiB257B7DhNllqbPWYI4o6f4N1pbmJneVcNtAbbIcgVWAg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":33582850,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj19mKACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpZaw//Rl7HyCQ3f27AjtQjJ/oDKEXbI3gVmbR1tZQe4R/5/8n441/N\r\nyRT9wn5zxA6ReWhCLgndRWHCqJg+667ffUnYFjNEo0t0Z0nWtqGST1EJmKQZ\r\nPcY13e5HLbyXhYjNQMaUlOwlWHygT7/BZ2OeNThAX4XWl7T70obu3Q0jX8W6\r\nM5EvhfXEayvlIpL7oW0vPeyV5sAuDNG/hPsv02i780/l0dpNLDqRXcoGTNy1\r\noQeLhWPDagFjHKSEYVGLXgj1JPGN8kV/4zPjOXKS4AavXBUlg8P9trjfNT4b\r\nvjSo4RTBREsOgA56HphrYDdGVLHEIbwelUKQAbZBjANpScunu+QA2x7JPTg/\r\ngJaC2S+da0vW24cDLQEoFTf8UlBgyOVmbkKYX2RHQd7thZleGPXWJk2ayEbY\r\nqe9zl1R6pozrgFWkQJI+xoUH5DXH+gbiRZZ0mxkheAUqEPP8bzjY3/oq+b69\r\nI/qOW5Z6o4zsDaFo+3Nii+qobiH1uvsho8QIksKJkLGmDP7vap/JWktNFF2K\r\n3q98nj6gLHIwtw67Ad66dFdSRQj85s1gtK7nZojHlngLxVNdRC3+rajWdt7k\r\nwo3iKoUALpeev20Pd5eFeb6ikcT9p9Dl6hGLozHoBg+ApG+zqcDbjah57utl\r\niizl3IclmEDznMu85mn4pBb15D4qmo9J/zI=\r\n=rjNj\r\n-----END PGP SIGNATURE-----\r\n"},"main":"./src/exports-commonjs.js","name":"streamr-client","types":"./types/src/index.d.ts","author":{"name":"Streamr Network AG","email":"contact@streamr.network"},"readme":"<p align=\"center\">\n  <a href=\"https://streamr.network\">\n    <img alt=\"Streamr\" src=\"https://raw.githubusercontent.com/streamr-dev/network-monorepo/main/packages/client/readme-header.png\" width=\"1320\" />\n  </a>\n</p>\n\n<h1 align=\"left\">\n  Streamr JavaScript Client\n</h1>\n\n![latest npm package version](https://img.shields.io/npm/v/streamr-client?label=latest)\n![GitHub stars](https://img.shields.io/github/stars/streamr-dev/network-monorepo?style=social)\n[![Discord Chat](https://img.shields.io/discord/801574432350928907.svg?label=Discord&logo=Discord&colorB=7289da)](https://discord.gg/FVtAph9cvz)\n\nThis library allows you to easily interact with the [Streamr Network](https://streamr.network) from JavaScript-based environments, such as browsers and [node.js](https://nodejs.org). The library wraps a Streamr light node for publishing and subscribing to messages, as well as contains convenience functions for creating and managing streams.\n\nPlease see the [Streamr project docs](https://streamr.network/docs) for more detailed documentation.\n\n## Contents\n- [Getting started](#getting-started)\n    - [Subscribing](#subscribing)\n    - [Publishing](#publishing)\n- [Setup](#setup)\n    - [Environments & frameworks](#environments-and-frameworks)\n- [Usage](#usage)\n    - [API reference](#api-reference)\n    - [Client creation](#client-creation)\n    - [Creating a stream](#creating-a-stream)\n    - [Subscribing to a stream](#subscribing-to-a-stream)\n    - [Publishing to a stream](#publishing-to-a-stream)\n    - [Requesting historical messages](#requesting-historical-messages)\n    - [Searching for streams](#searching-for-streams)\n    - [Interacting with the `Stream` object](#interacting-with-the-stream-object)\n     - [Getting existing streams](#getting-existing-streams)\n    - [Stream access control](#stream-access-control)\n    - [Enabling storage](#enabling-storage)\n    - [Utility functions](#utility-functions)\n- [Advanced usage](#advanced-usage)\n    - [Metrics publishing](#metrics-publishing)\n    - [Stream partitioning](#stream-partitioning)\n    - [Disable message ordering and gap filling](#disable-message-ordering-and-gap-filling)\n    - [Encryption keys](#encryption-keys)\n    - [Proxy publishing and subscribing](#proxy-publishing-and-subscribing)\n    - [Logging](#logging)\n\n## Getting started\n\n### Subscribing\n```js\nconst streamId = 'streamr.eth/demos/helsinki-trams'\n\nstreamr.subscribe(streamId, (message) => {\n    // handle for individual messages\n})\n\n```\n\n### Publishing\n```js\n// Requires MATIC tokens (Polygon blockchain gas token)\nconst stream = await streamr.createStream({\n    id: '/foo/bar'\n})\n\nawait stream.publish({ timestamp: Date.now() })\n```\n\n\nMore examples can be found in the [examples repo](https://github.com/streamr-dev/examples).\n___\n\n\n## Setup\n\n### Installation\nThe client is available on [npm](https://www.npmjs.com/package/streamr-client) and can be installed simply by:\n\n```\nnpm install streamr-client\n```\n\n### Importing `streamr-client`\nTo use with react please see [streamr-client-react](https://github.com/streamr-dev/streamr-client-react)\n\nIf using TypeScript you can import the library with:\n```js\nimport { StreamrClient } from 'streamr-client'\n```\nIf using Node.js you can import the library with:\n\n```js\nconst { StreamrClient } = require('streamr-client')\n```\n\n### Environments and frameworks\n\n#### NodeJS\nNodeJS `16.13.x` is the minimum required version. NodeJS `18.13.x`, NPM `8.x` and later versions are recommended.\n\n#### Browser (Website/WebApps)\nFor usage in the browser include the latest build, e.g. by including a `<script>` tag pointing at a CDN:\n\n```html\n<script src=\"https://unpkg.com/streamr-client@latest/streamr-client.web.js\"></script>\n```\n\n#### Browser extension\nDue to the stricter security rules inside browser extensions you must use the web build version of the Streamr Client.\n\n#### React Native\nWe are actively working on React Native compatibility but currently the Streamr JavaScript Client is not compatible with React Native. To connect, pull or push data into the Streamr Network, use the [Broker integration pattern](https://streamr.network/docs/streamr-network/connecting-applications).\n\n___\n## Usage\n\n### API reference\nSee https://api-docs.streamr.network/client/v7.3/index.html\n\n### Client creation\nIn Streamr, Ethereum accounts are used for identity. You can generate an Ethereum private key using any Ethereum wallet, or you can use the utility function [`StreamrClient.generateEthereumAccount()`](#utility-functions), which returns the address and private key of a fresh Ethereum account. A private key is not required if you are only subscribing to public streams on the Network.\n\n```js\nconst streamr = new StreamrClient({\n    auth: {\n        privateKey: 'your-private-key'\n    }\n})\n```\n\nAuthenticating with an Ethereum private key contained in an Ethereum (web3) provider (e.g. MetaMask):\n```js\nconst streamr = new StreamrClient({\n    auth: {\n        ethereum: window.ethereum,\n    }\n})\n```\n\nYou can also create an anonymous client instance that can interact with public streams:\n```js\nconst streamr = new StreamrClient()\n```\n\nBy default, the `StreamrClient` publishes telemetry metrics to the network at regular intervals. See [Metrics publishing](#metrics-publishing).\n\n### Creating a stream\n```js\n// Requires MATIC tokens (Polygon blockchain gas token)\nconst stream = await streamr.createStream({\n    id: '/foo/bar'\n})\n\nconsole.log(stream.id) // e.g. `0x12345.../foo/bar`\n```\n\nYou can also create a stream by defining the address in the provided id. Please note that the creation will only succeed if you specify the same address as provided for authentication when creating the `streamr` instance:\n```js\n// Requires MATIC tokens (Polygon blockchain gas token)\nconst stream = await client.createStream({\n    id: `${address}/foo/bar`\n})\n\nconsole.log(stream.id) // e.g. `0x12345.../foo/bar`\n```\n\nMore information on Stream IDs can be found under the [stream creation project docs](https://streamr.network/docs/streams/creating-streams)\n\n### Subscribing to a stream\n```js\nconst subscription = await streamr.subscribe(\n    streamId,\n    (content, metadata) => { ... }\n)\n```\nThe callback's first parameter, `content`, contains the value given to the `publish` method.\n\nThe second parameter `metadata` contains metadata about the message, e.g. timestamp.\n\nUnsubscribing from an existent subscription:\n```js\nawait streamr.unsubscribe(streamId)\n// or, unsubscribe them all:\nconst streams = await streamr.unsubscribe()\n```\n\nGetting all streams the client is subscribed to:\n```js\nconst subscriptions = streamr.getSubscriptions()\n```\n### Publishing to a stream\n\n```js\n// Here's our example data point\nconst msg = {\n    temperature: 25.4,\n    humidity: 10,\n    happy: true\n}\n\n// Publish using the stream id only\nawait streamr.publish(streamId, msg)\n\n// Publish with a specific timestamp as a Date object (default is now)\nawait streamr.publish(streamId, msg, { timestamp: new Date(1546300800123) })\n\n// Publish with a specific timestamp in ms\nawait streamr.publish(streamId, msg, { timestamp: 1546300800123 })\n\n// Publish with a specific timestamp as a ISO8601 string\nawait streamr.publish(streamId, msg, { timestamp: '2019-01-01T00:00:00.123Z' })\n\n// For convenience, stream.publish(...) equals streamr.publish(stream, ...)\nawait stream.publish(msg)\n```\n\n### Requesting historical messages\nBy default `subscribe` will not request historical messages.\n\nYou can fetch historical messages with the `resend` method:\n```js\n// Fetches the last 10 messages stored for the stream\nconst resend1 = await streamr.resend(\n    streamId,\n    {\n        last: 10,\n    },\n    onMessage\n)\n```\n\nAlternatively you can fetch historical messages and subscribe to real-time messages:\n```js\n// Fetches the last 10 messages and subscribes to the stream\nconst sub1 = await streamr.subscribe({\n    id: streamId,\n    resend: {\n        last: 10,\n    }\n}, onMessage)\n```\nIn order to fetch historical messages the stream needs to have [storage enabled](#enabling-storage).\n\nResend from a specific timestamp up to the newest message:\n```js\nconst sub2 = await streamr.resend(\n    streamId,\n    {\n        from: {\n            timestamp: (Date.now() - 1000 * 60 * 5), // 5 minutes ago\n            sequenceNumber: 0, // optional\n        },\n        publisher: '0x12345...', // optional\n    }\n)\n```\nResend a range of messages:\n```js\nconst sub3 = await streamr.resend(\n    streamId,\n    {\n        from: {\n            timestamp: (Date.now() - 1000 * 60 * 10), // 10 minutes ago\n        },\n        to: {\n            timestamp: (Date.now() - 1000 * 60 * 5), // 5 minutes ago\n        },\n        // when using from and to the following parameters are optional\n        // but, if specified, both must be present\n        publisher: '0x12345...',\n        msgChainId: 'ihuzetvg0c88ydd82z5o',\n    }\n)\n```\nIf you choose one of the above resend options when subscribing, you can listen on the completion of this resend by doing the following:\n\n```js\nconst sub = await streamr.subscribe(options)\nsub.once('resendComplete', () => {\n    console.log('Received all requested historical messages! Now switching to real time!')\n})\n```\n\nNote that only one of the resend options can be used for a particular subscription.\n\n### Searching for streams\nYou can search for streams by specifying a search term:\n```js\nconst streams = await streamr.searchStreams('foo')\n```\nAlternatively or additionally to the search term, you can search for streams based on permissions.\n\nTo get all streams for which a user has any direct permission:\n```js\nconst streams = await streamr.searchStreams('foo', {\n    user: '0x12345...'\n})\n```\nTo get all streams for which a user has any permission (direct or public):\n```js\nconst streams = await streamr.searchStreams('foo', {\n    user: '0x12345...',\n    allowPublic: true\n})\n```\n\nIt is also possible to filter by specific permissions by using `allOf` and `anyOf` properties. The `allOf` property should be preferred over `anyOf` when possible due to better query performance.\n\nIf you want to find the streams you can subscribe to:\n```js\nconst streams = await streamr.searchStreams(undefined, {\n    user: '0x12345...',\n    allOf: [StreamPermission.SUBSCRIBE],\n    allowPublic: true\n})\n```\n___\n### Interacting with the `Stream` object\nThe `Stream` type provides a convenient way to interact with a stream without having to repeatedly pass Stream IDs.\n#### Getting existing streams\n```js\nconst stream = await streamr.getStream(streamId)\n```\n\nThe method getOrCreateStream gets the stream if it exists, and if not, creates it:\n```js\n// May require MATIC tokens (Polygon blockchain gas token)\nconst stream = await streamr.getOrCreateStream({\n    id: streamId\n})\n```\n\n#### Stream access control\n\nThere are 5 different stream permissions:\n- StreamPermission.PUBLISH\n- StreamPermission.SUBSCRIBE\n- StreamPermission.EDIT\n- StreamPermission.DELETE\n- StreamPermission.GRANT\n\nYou can import the `StreamPermission` enum with:\n```js\nconst { StreamPermission } = require('streamr-client')\n```\n\nFor each stream + user there can be a permission assignment containing a subset of those permissions. It is also possible to grant public permissions for streams (only `StreamPermission.PUBLISH` and `StreamPermission.SUBSCRIBE`). If a stream has e.g. a public subscribe permissions, it means that anyone can subscribe to that stream.\n\n\nTo grant a permission for a user:\n```js\n// Requires MATIC tokens (Polygon blockchain gas token)\nawait stream.grantPermissions({\n    user: '0x12345...',\n    permissions: [StreamPermission.PUBLISH],\n})\n```\nOr to grant a public permission:\n```js\nawait stream.grantPermissions({\n    public: true,\n    permissions: [StreamPermission.SUBSCRIBE]\n})\n```\nTo revoke a permission from a user:\n```js\n// Requires MATIC tokens (Polygon blockchain gas token)\nawait stream.revokePermissions({\n    user: '0x12345...',\n    permissions: [StreamPermission.PUBLISH]\n})\n```\nOr revoke public permission:\n```js\nawait stream.revokePermissions({\n    public: true,\n    permissions: [StreamPermission.SUBSCRIBE]\n})\n```\n\n\nThe method `streamr.setPermissions` can be used to set an exact set of permissions for one or more streams. Note that if there are existing permissions for the same users in a stream, the previous permissions are overwritten. Note that this method cannot be used from a stream, but via the `StreamrClient` instance:\n\n```js\n// Requires MATIC tokens (Polygon blockchain gas token)\nawait streamr.setPermissions({\n    streamId,\n    assignments: [\n        {\n            user: '0x11111...',\n            permissions: [StreamPermission.EDIT]\n        }, {\n            user: '0x22222...'\n            permissions: [StreamPermission.GRANT]\n        }, {\n            public: true,\n            permissions: [StreamPermission.PUBLISH, StreamPermission.SUBSCRIBE]\n        }\n    ]\n})\n```\n\nYou can query the existence of a permission with `hasPermission()`. Usually you want to use `allowPublic: true` flag so that also the existence of a public permission is checked:\n```js\nawait stream.hasPermission({\n    permission: StreamPermission.PUBLISH,\n    user: '0x12345...',\n    allowPublic: true\n}\n```\n\nThe full list of permissions for a stream can be queried by calling `stream.getPermissions()`:\n```js\nconst permissions = await stream.getPermissions()\n```\nThe returned value is an array of permissions containing an item for each user, and possibly one for public permissions:\n```js\npermissions = [\n    { user: '0x12345...', permissions: ['subscribe', 'publish'] },\n    { public: true, permissions: ['subscribe']}\n]\n```\n\n#### Updating a stream\nTo update the description of a stream:\n```js\n// Requires MATIC tokens (Polygon blockchain gas token)\nawait stream.update({\n    description: 'New description'\n})\n```\n\n\n#### Deleting a stream\nTo delete a stream:\n```js\n// Requires MATIC tokens (Polygon blockchain gas token)\nawait stream.delete()\n```\n\n\n\n### Enabling storage\n\nYou can enable storage on your streams to retain historical messages and access it later via `resend`. By default storage is not enabled on streams. You can enable it with:\n\n```js\nconst { StreamrClient, STREAMR_STORAGE_NODE_GERMANY } = require('streamr-client')\n...\n// assign a stream to a storage node\nawait stream.addToStorageNode(STREAMR_STORAGE_NODE_GERMANY)\n```\nOther operations with storage:\n```js\n// remove the stream from a storage node\nawait stream.removeFromStorageNode(STREAMR_STORAGE_NODE_GERMANY)\n// fetch the storage nodes for a stream\nconst storageNodes = stream.getStorageNodes()\n```\n\n### Utility functions\n\nThe static function `StreamrClient.generateEthereumAccount()` generates a new Ethereum private key and returns an object with fields `address` and `privateKey`.\n```js\nconst { address, privateKey } = StreamrClient.generateEthereumAccount()\n```\nIn order to retrieve the client's address an async call must me made to `streamr.getAddress`\n```js\nconst address = await streamr.getAddress()\n```\n\n## Advanced usage\n\n### Metrics publishing\n\nBy default, the `StreamrClient` publishes metrics to the network at regular intervals. The metrics include, for example, information about data volumes passing through the node, and are attributed to your node id. Here's the content of the metrics messages:\n\n```\n{\n    node: {\n        publishMessagesPerSecond: number\n        publishBytesPerSecond: number\n        sendMessagesPerSecond: number\n        sendBytesPerSecond: number\n        receiveMessagesPerSecond: number\n        receiveBytesPerSecond: number\n        connectionAverageCount: number\n        connectionTotalFailureCount: number\n    },\n    period: {\n        start: number\n        end: number\n    }\n}\n```\n\nIf you don't want to publish metrics, you can turn it off in the client configuration:\n\n```\nconst streamr = new StreamrClient({\n    ...\n    metrics: false\n})\n```\n\nIf you want to use custom stream and/or reporting periods, you can specify the details like this:\n```\nconst streamr = new StreamrClient({\n    ...\n    metrics: {\n        periods: [{\n            duration: 3600000, // in milliseconds\n            streamId: \"my-metrics-stream.eth/hour\"\n        }]\n    }\n})\n```\n\n\n\n### Stream partitioning\n\nPartitioning (sharding) enables streams to scale horizontally. This section describes how to use partitioned streams via this library. To learn the basics of partitioning, see [the docs](https://streamr.network/docs/streams#partitioning).\n\n#### A note on stream ids and partitions\nThe public methods of the client generally support the following three ways of defining a stream:\n```js\n// Stream id as a string:\nconst streamId = `${address}/foo/bar`\n\n// Stream id + partition as a string\nconst streamId = `${address}/foo/bar#4`\n\n// Stream id + partition as an object\nconst streamId = {\n    id: `${address}/foo/bar`,\n    partition: 4\n}\n```\n\n#### Creating partitioned streams\n\nBy default, streams only have 1 partition when they are created. The partition count can be set to any number between 1 and 100. An example of creating a partitioned stream:\n\n```js\n// Requires MATIC tokens (Polygon blockchain gas token)\nconst stream = await streamr.createStream({\n    id: `/foo/bar`,\n    partitions: 10,\n})\nconsole.log(`Stream created: ${stream.id}. It has ${stream.getMetadata().partitions} partitions.`)\n```\n\n#### Publishing to partitioned streams\n\nIn most use cases, a user wants related messages (e.g. messages from a particular device) to be assigned to the same partition, so that the messages retain a deterministic order and reach the same subscriber(s) to allow them to compute stateful aggregates correctly.\n\nYou can specify the partition number as follows:\n```js\nawait streamr.publish({\n    id: `${address}/foo/bar`,\n    partition: 4\n}, msg)\n```\n\nThe library alternatively allows the user to choose a _partition key_, which simplifies publishing to partitioned streams by not requiring the user to assign a partition number explicitly. The same partition key always maps to the same partition. In an IoT use case, the device id can be used as partition key; in user interaction data it could be the user id, and so on.\n\nThe partition key can be given as an argument to the `publish` methods, and the library assigns a deterministic partition number automatically:\n\n```js\nawait stream.publish(\n    msg,\n    {\n        partitionKey: msg.vehicleId\n    }\n)\n```\n\n#### Subscribing to partitioned streams\n\nBy default, the client subscribes to the first partition (partition `0`) of a stream. Be aware: this behavior will change in the future so that it will subscribe to _all_ partitions by default.\n\nThe partition number can be explicitly given in `subscribe`:\n\n```js\nconst sub = await streamr.subscribe({\n    id: streamId,\n    partition: 4\n}, (content) => {\n    console.log('Got message %o', content)\n})\n```\n\nIf you want to subscribe to multiple partitions:\n```js\nconst onMessage = (content, streamMessage) => {\n    console.log('Got message %o from partition %d', content, streamMessage.getStreamPartition())\n}\n\nawait Promise.all([2, 3, 4].map(async (partition) => {\n    await streamr.subscribe({\n        id: streamId,\n        partition,\n    }, onMessage)\n}))\n```\n\n### Disable message ordering and gap filling\nIf your use case tolerates missing messages and message arriving out-of-order, you can turn off message ordering and gap filling when creating a instance of the client:\n```js\nconst streamr = new StreamrClient({\n    auth: { ... },\n    orderMessages: false,\n    gapFill: false\n})\n```\nBoth of these properties should be disabled in tandem for message ordering and gap filling to be properly turned off.\n\nBy disabling message ordering your application won't perform any filling nor sorting, dispatching messages as they come (faster) but without granting their collective integrity.\n\n\n### Encryption keys\n\nMessages published to a non-public stream are always encrypted. The publishing client creates the encryption keys and delivers them to the subscribers automatically. In most use cases, there is no need to manage encryption keys manually.\n\n#### Typical use cases\n\nA new encryption key is generated when publishing activity to a stream starts. The keys don't change during the lifetime of a client unless explicitly updated.\n\nAt any given time a subscriber can request a key from a publisher. When the publisher receives a request, it checks whether the subscriber has valid `StreamPermission.SUBSCRIBE` permission to the stream. If a valid permission exists, the client sends the encryption key to the subscriber. The subscriber can then use the key to decrypt messages which are encrypted with that key.\n\nTypically subscribers query the current encryption key. But if they need to access to historical data, they may query previous encryption keys. A publisher client keeps track of all previous encryption keys in a local database, so it can respond to historical encryption key queries automatically. Therefore the publisher needs to stay online if historical decryption of its data is something that should be supported.\n\n#### Manual key update\n\nYou can manually update the encryption key by calling `client.updateEncryptionKey(...)`. This triggers the creation of a new encryption key, after which the client starts to use that to encrypt published messages.\n\nIn practice, an update is needed if:\n\n- You want to prevent new subscribers from reading historical messages. When you update the key, the new subscribers get the new key. But as the historical data is encrypted with some previous key, those messages aren't decryptable by the new subscribers.\n- You want to prevent expired subscribers from reading new messages. When you update the key, but you don't distribute the new key to the expired subscribers, they aren't able to decrypt new messages.\n\nBoth of the use cases are covered if you call:\n```\nclient.updateEncryptionKey({\n    streamId,\n    distributionMethod: 'rekey'\n})\n```\n\nYou may want to call this method regularly (e.g. daily/weekly). Alternatively you can call it anytime you observe new expired subscribers (that is, someone bought your data stream for a limited period of time, and that period has now elapsed).\n\n#### Optimization: key rotation\n\nYou can optimize the key distribution by using `rotate` instead of `rekey`. The optimization is applicable if subscriptions haven't expired or been removed. In that situation you can update the key by calling:\n```\nclient.updateEncryptionKey({\n    streamId,\n    distributionMethod: 'rotate'\n})\n```\n\nIn detail, the difference between the methods is:\n- In `rekey` method, the client sends the new key individually to each subscriber. Every subscriber receives a separate message which is encrypted with their public RSA key. The `StreamPermission.SUBSCRIBE` permission is checked by the publisher for each subscriber before a key is sent.\n- In optimized `rotate` method, the key is broadcasted to the network in the metadata of the next message. The key is encrypted with the previous encryption key and therefore subscribers can use it only if they know the previous key (https://en.wikipedia.org/wiki/Forward_secrecy). As the key is broadcasted to everyone, no permissions are checked. Note that recently expired subscribers most likely have the previous key, therefore they can use that new key, too.\n\n#### Pre-agreed keys\n\nIf you don't want to exchange the keys via the network, you can use pre-agreed keys like this:\n\n```\nconst key = new GroupKey('key-id', crypto.randomBytes(32))\npublisher.updateEncryptionKey({\n    key,\n    streamId,\n    distibutionMethod: 'rekey'\n})\nsubscriber.addEncryptionKey(key, streamId)\n```\n\n#### Configuration\n\nThere are two optional configuration options related to encryption keys:\n- `decryption.keyRequestTimeout`: max time (in milliseconds) to wait before a key request timeouts\n- `decryption.maxKeyRequestsPerSecond`: max count of key request to be sent within a second (i.e. it throttles the requests if it receives messages from many new publishers within a short period of time)\n\n### Proxy publishing and subscribing\n\nIn some cases the client might be interested in publishing messages without participating in the stream's message propagation. With this option the nodes can sign all messages they publish by themselves. Alternatively, a client could open a WS connection to a broker node and allow the broker to handle signing with its private key.\n\nSetting subscribe proxies can be useful for cases where broker nodes with public IP addresses do not exist in a stream.\n\nProxy publishing and subscribing are handled on the network overlay level. This means that there is no need to know the IP address of the node that will be used as a proxy. Instead, the node needs to know the ID of the network node it wants to connect to. It is not possible to set publish / subscribe proxies for a stream that is already being \"traditionally\" subscribed or published to and vice versa.\n\n```js\n\n// Open publish proxy to multiple nodes on stream\nawait publishingClient.openProxyConnections(stream, ['0x11111...', '0x22222...'], ProxyDirection.PUBLISH)\n\n// Remove publish proxy to multiple nodes on stream\nawait publishingClient.closeProxyConnections(stream, ['0x11111...', '0x22222...'], ProxyDirection.PUBLISH)\n\n// Open publish proxy to multiple nodes on stream\nawait publishingClient.openProxyConnections(stream, ['0x11111...', '0x22222...'], ProxyDirection.SUBSCRIBE)\n\n// Remove publish proxy to multiple nodes on stream\nawait publishingClient.closeProxyConnections(stream, ['0x11111...', '0x22222...'], ProxyDirection.SUBSCRIBE)\n```\n\nIMPORTANT: The node that is used as a proxy must have set the option on the network layer to accept incoming proxy connections and must have joined to the stream that a proxy connection is wanted for.\n\nExample client config:\n\n```json\n{\n    ...\n    \"network\": {\n        ...\n        \"acceptProxyConnections\": true\n    }\n}\n```\n\nExample broker config\n\n```json\n{\n    ...\n    \"client\": {\n        ...\n        \"network\": {\n            ...\n            \"acceptProxyConnections\": true\n        }\n    },\n    \"plugins\": {\n        ...\n        \"subscriber\": {\n            \"streams\": [\n                {\n                    \"streamId\": \"STREAM_ID\",\n                    \"streamPartition\": 0\n                },\n                {\n                    \"streamId\": \"STREAM_ID2\",\n                    \"streamPartition\": 0\n                },\n            ]\n        }\n    }\n}\n```\n\n### Logging\n\nThere are two ways to set a desired logging level.\n\nYou can pass the logging level in the StreamrClient constructor as follows:\n```ts\nconst streamr = new StreamrClient({\n  logLevel: 'debug',\n  // ... more options\n})\n```\n\nAlternatively, when running your application in Node.js, you can provide the\nlogging level via the environment variable `LOG_LEVEL`, for example, by running\nyour application as follows:\n\n```bash\nLOG_LEVEL=trace node your-app.js\n```\n\nWhen defining both the environment variable takes precedence. Default logging\nlevel is `info`. Valid logging levels are `silent`, `fatal`, `error`, `warn`,\n`info`, `debug`, and `trace`.\n","browser":"./streamr-client.web.js","exports":{"browser":"./streamr-client.web.js","default":{"import":"./src/exports-esm.mjs","require":"./src/exports-commonjs.js"}},"gitHead":"2e833728936936d91fe6de25dc3343da99931761","license":"Apache-2.0","_npmUser":{"name":"harbu","email":"harbuzen@gmail.com"},"homepage":"https://github.com/streamr-dev/network#readme","#IMPORTANT":"babel-runtime must be in dependencies, not devDependencies","repository":{"url":"git+https://github.com/streamr-dev/network.git","type":"git","directory":"packages/client"},"_npmVersion":"9.1.3","description":"JavaScript client library for Streamr","directories":{},"maintainers":[{"name":"samigabor","email":"samoila.gabor@yahoo.com"},{"name":"kare","email":"kare.nuorteva@me.com"},{"name":"fonty1","email":"mr.matto@gmail.com"},{"name":"hpihkala","email":"henri.pihkala@streamr.com"},{"name":"tumppi","email":"tuomas.koponen@streamr.com"},{"name":"harbu","email":"harbuzen@gmail.com"},{"name":"mariusz_io","email":"mariusz@mariusz.io"},{"name":"pzsavola","email":"petri.savolainen@spaceify.net"},{"name":"mmartinmo","email":"martin.moravek@streamr.com"},{"name":"juslesan","email":"santeri.juslenius@gmail.com"},{"name":"jtakalai","email":"juuso.takalainen@streamr.com"},{"name":"streamr-dev","email":"devtools@streamr.com"},{"name":"teogeb","email":"teo@streamr.com"},{"name":"samt1803","email":"samt1803@gmail.com"}],"_nodeVersion":"16.14.2","dependencies":{"ajv":"^8.8.2","mem":"^8.1.1","heap":"^0.2.6","sha3":"^2.1.4","uuid":"^8.3.2","lodash":"^4.17.21","split2":"^3.2.2","sqlite":"^4.0.23","core-js":"^3.19.1","p-limit":"^3.1.0","sqlite3":"^5.0.3","lit-siwe":"^1.1.8","tsyringe":"^4.6.0","env-paths":"^2.2.1","p-memoize":"4.0.3","quick-lru":"^6.0.1","secp256k1":"^4.0.2","bufferutil":"^4.0.5","idb-keyval":"^5.1.5","node-fetch":"^2.6.6","p-throttle":"4.0.0","ajv-formats":"^2.1.1","ts-toolbelt":"^9.6.0","eventemitter3":"^4.0.7","@babel/runtime":"^7.16.3","@streamr/utils":"v7.4.0-beta.1","utf-8-validate":"^5.0.7","readable-stream":"^3.6.0","reflect-metadata":"^0.1.13","@streamr/protocol":"v7.4.0-beta.1","@ethersproject/abi":"^5.5.0","@ethersproject/web":"^5.5.0","@ethersproject/bytes":"^5.5.0","@ethersproject/wallet":"^5.5.0","@streamr/network-node":"v7.4.0-beta.1","@babel/runtime-corejs3":"^7.16.3","@ethersproject/address":"^5.5.0","@ethersproject/bignumber":"^5.5.0","@ethersproject/constants":"^5.5.0","@ethersproject/contracts":"^5.5.0","@ethersproject/providers":"^5.5.0","strict-event-emitter-types":"^2.0.0","@ethersproject/transactions":"^5.5.0","@lit-protocol/lit-node-client":"2.1.16","@ethersproject/abstract-signer":"^5.5.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"util":"^0.12.4","bytes":"^3.1.1","buffer":"^6.0.3","express":"^4.17.1","typedoc":"^0.23.20","webpack":"^5.64.1","benchmark":"^2.1.4","ts-loader":"^9.3.1","weak-napi":"^2.0.2","nightwatch":"^1.7.12","@babel/core":"^7.16.0","@types/heap":"^0.2.28","@types/uuid":"^8.3.1","webpack-cli":"^4.9.1","babel-loader":"^8.2.3","chromedriver":"^108.0.0","concurrently":"^6.4.0","@types/lodash":"^4.14.175","@types/split2":"^3.2.1","array-shuffle":"^2.0.0","ts-essentials":"^9.3.0","webpack-merge":"^5.8.0","@types/secp256k1":"^4.0.3","@babel/preset-env":"^7.16.4","@types/node-fetch":"^2.5.12","crypto-browserify":"^3.12.0","jest-leak-detector":"^27.3.1","@streamr/test-utils":"v7.4.0-beta.1","babel-plugin-lodash":"^3.3.4","eslint-plugin-import":"^2.25.3","lodash-webpack-plugin":"^0.11.6","terser-webpack-plugin":"^5.2.5","webpack-bundle-analyzer":"^4.5.0","@babel/preset-typescript":"^7.16.0","@ethersproject/wordlists":"^5.5.0","git-revision-webpack-plugin":"^5.0.0","node-polyfill-webpack-plugin":"^1.1.4","@babel/plugin-transform-runtime":"^7.16.4","babel-plugin-add-module-exports":"^1.0.4","@babel/plugin-proposal-decorators":"^7.16.4","@babel/plugin-transform-modules-commonjs":"^7.16.0","babel-plugin-transform-typescript-metadata":"^0.3.2"},"optionalDependencies":{"bufferutil":"^4.0.5","utf-8-validate":"^5.0.7"},"_npmOperationalInternal":{"tmp":"tmp/streamr-client_7.4.0-beta.1_1675090314118_0.3061666536969785","host":"s3://npm-registry-packages"},"_id":"streamr-client@7.4.0-beta.1","version":"7.4.0-beta.1"}