infinispan 0.9.0 → 0.10.0

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.
Files changed (58) hide show
  1. package/documentation/asciidoc/stories/assembly_client_usage_examples.adoc +2 -8
  2. package/documentation/asciidoc/stories/{assembly_configuration.adoc → assembly_installation_configuration.adoc} +6 -4
  3. package/documentation/asciidoc/titles/js_client.asciidoc +1 -0
  4. package/documentation/asciidoc/titles/stories.adoc +1 -2
  5. package/documentation/asciidoc/topics/attributes/community-attributes.adoc +1 -1
  6. package/documentation/asciidoc/topics/attributes/downstream-attributes.adoc +0 -2
  7. package/documentation/asciidoc/topics/code_examples/authentication-digest.js +3 -2
  8. package/documentation/asciidoc/topics/code_examples/authentication-external.js +3 -2
  9. package/documentation/asciidoc/topics/code_examples/authentication-oauthbearer.js +3 -2
  10. package/documentation/asciidoc/topics/code_examples/authentication-plain.js +3 -2
  11. package/documentation/asciidoc/topics/code_examples/authentication-scram.js +3 -2
  12. package/documentation/asciidoc/topics/code_examples/await-single-entries.js +1 -1
  13. package/documentation/asciidoc/topics/code_examples/conditional-operations.js +7 -1
  14. package/documentation/asciidoc/topics/code_examples/connection-multiple-servers.js +5 -1
  15. package/documentation/asciidoc/topics/code_examples/data-types.js +2 -2
  16. package/documentation/asciidoc/topics/code_examples/ephemeral-data.js +11 -6
  17. package/documentation/asciidoc/topics/code_examples/hello-world.js +13 -1
  18. package/documentation/asciidoc/topics/code_examples/key-value-converter.js +3 -4
  19. package/documentation/asciidoc/topics/code_examples/multiple-entries.js +13 -2
  20. package/documentation/asciidoc/topics/code_examples/register-event-listener.js +8 -4
  21. package/documentation/asciidoc/topics/code_examples/sample-script-execute.js +6 -1
  22. package/documentation/asciidoc/topics/code_examples/single-entries.js +13 -2
  23. package/documentation/asciidoc/topics/proc_configuring_connections.adoc +8 -9
  24. package/documentation/asciidoc/topics/proc_installing_clients.adoc +23 -5
  25. package/documentation/asciidoc/topics/ref_client_usage.adoc +116 -0
  26. package/lib/codec.js +153 -2
  27. package/lib/infinispan.js +27 -1
  28. package/lib/io.js +14 -8
  29. package/lib/protocols.js +129 -4
  30. package/lib/protostream/message-wrapping.proto +134 -0
  31. package/lib/protostream/query.proto +122 -0
  32. package/lib/sasl/bitops.js +5 -7
  33. package/lib/sasl/factory.js +71 -0
  34. package/lib/utils.js +1 -1
  35. package/memory-profiling/helper.js +9 -0
  36. package/memory-profiling/infinispan_memory_many_get.js +1 -3
  37. package/memory-profiling/infinispan_memory_one_get.js +6 -4
  38. package/package.json +7 -12
  39. package/run-servers.sh +1 -1
  40. package/spec/codec_spec.js +7 -7
  41. package/spec/configs/infinispan-clustered.xml +17 -14
  42. package/spec/configs/infinispan-ssl.xml +25 -22
  43. package/spec/configs/infinispan-xsite-EARTH.xml +17 -14
  44. package/spec/configs/infinispan-xsite-MOON.xml +14 -11
  45. package/spec/configs/infinispan.xml +22 -13
  46. package/spec/protostream_spec.js +237 -0
  47. package/spec/utils/testing.js +1 -3
  48. package/documentation/asciidoc/stories/assembly_getting_started.adoc +0 -11
  49. package/documentation/asciidoc/topics/community-attributes.adoc +0 -10
  50. package/documentation/asciidoc/topics/downstream-attributes.adoc +0 -10
  51. package/documentation/asciidoc/topics/proc_executing_scripts.adoc +0 -16
  52. package/documentation/asciidoc/topics/proc_registering_event_listeners.adoc +0 -31
  53. package/documentation/asciidoc/topics/proc_using_async_await.adoc +0 -23
  54. package/documentation/asciidoc/topics/proc_using_conditional_operations.adoc +0 -7
  55. package/documentation/asciidoc/topics/proc_working_ephemeral_data.adoc +0 -7
  56. package/documentation/asciidoc/topics/proc_working_multiple_entries.adoc +0 -7
  57. package/documentation/asciidoc/topics/proc_working_single_entries_statistics.adoc +0 -7
  58. package/documentation/asciidoc/topics/ref_basic_usage.adoc +0 -8
@@ -1,15 +1,9 @@
1
1
  [id='client-usage-examples']
2
2
  :context: client-usage-examples
3
3
  = Using {hr_js} clients
4
- This section provides code examples that show you how to use {hr_js} clients to perform various operations.
4
+ Take a look at some examples for using the {hr_js} client with {brandname}.
5
5
 
6
- include::{topics}/proc_working_single_entries_statistics.adoc[leveloffset=+1]
7
- include::{topics}/proc_using_conditional_operations.adoc[leveloffset=+1]
8
- include::{topics}/proc_working_multiple_entries.adoc[leveloffset=+1]
9
- include::{topics}/proc_working_ephemeral_data.adoc[leveloffset=+1]
10
- include::{topics}/proc_registering_event_listeners.adoc[leveloffset=+1]
11
- include::{topics}/proc_executing_scripts.adoc[leveloffset=+1]
12
- include::{topics}/proc_using_async_await.adoc[leveloffset=+1]
6
+ include::{topics}/ref_client_usage.adoc[leveloffset=+1]
13
7
 
14
8
  // Restore the parent context.
15
9
  ifdef::parent-context[:context: {parent-context}]
@@ -1,8 +1,10 @@
1
- [id='client-configuration']
2
- :context: client-configuration
3
- = Configuring {hr_js} clients
4
- Configure {hr_js} clients to connect to {brandname} Server, use different media types for keys and values, and adjust levels for log messages.
1
+ [id='install-configure']
2
+ :context: install-configure
3
+ = Installing and configuring {hr_js} clients
4
+ Ensure your system meets requirements before installing the {hr_js} client.
5
+ You can then configure {hr_js} clients to connect to {brandname} Server, use different media types for keys and values, and customize logging.
5
6
 
7
+ include::{topics}/proc_installing_clients.adoc[leveloffset=+1]
6
8
  include::{topics}/proc_configuring_connections.adoc[leveloffset=+1]
7
9
  include::{topics}/proc_configuring_connections_xsite.adoc[leveloffset=+2]
8
10
  include::{topics}/proc_switching_clusters.adoc[leveloffset=+2]
@@ -9,6 +9,7 @@ include::{topics}/attributes/community-attributes.adoc[]
9
9
  //Downstream
10
10
  //include::{topics}/attributes/downstream-attributes.adoc[]
11
11
  //:downstream:
12
+ //:rhdg-install-npmrepo:
12
13
 
13
14
  //Title attributes
14
15
  :toc2:
@@ -1,6 +1,5 @@
1
1
  //Reference user stories or topics.
2
2
  //Please review authoring guidelines in the Contributors Guide.
3
3
 
4
- include::{stories}/assembly_getting_started.adoc[leveloffset=+1]
5
- include::{stories}/assembly_configuration.adoc[leveloffset=+1]
4
+ include::{stories}/assembly_installation_configuration.adoc[leveloffset=+1]
6
5
  include::{stories}/assembly_client_usage_examples.adoc[leveloffset=+1]
@@ -3,6 +3,6 @@
3
3
 
4
4
  :doc_home: https://infinispan.org/documentation/
5
5
  :download_url: https://infinispan.org/hotrod-clients
6
- :js_api_docs: https://docs.jboss.org/infinispan/hotrod-clients/javascript/1.0/apidocs/
6
+ :node_docs: https://docs.jboss.org/infinispan/hotrod-clients/javascript/1.0/apidocs/
7
7
  :server_docs: https://infinispan.org/docs/stable/titles/server/server.html
8
8
  :code_tutorials: https://github.com/infinispan/infinispan-simple-tutorials/
@@ -1,4 +1,2 @@
1
1
  :brandname: Data Grid
2
2
  :hr_js: Hot Rod JS
3
-
4
- :js_api_docs: https://access.redhat.com/webassets/avalon/d/red-hat-data-grid/8.2/node/
@@ -1,5 +1,6 @@
1
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
2
- {
1
+ var connected = infinispan.client(
2
+ {port: 11222, host: '127.0.0.1'},
3
+ {
3
4
  authentication: {
4
5
  enabled: true,
5
6
  saslMechanism: 'DIGEST-MD5',
@@ -1,5 +1,6 @@
1
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
2
- {
1
+ var connected = infinispan.client(
2
+ {port: 11222, host: '127.0.0.1'},
3
+ {
3
4
  authentication: {
4
5
  enabled: true,
5
6
  saslMechanism: 'EXTERNAL'
@@ -1,5 +1,6 @@
1
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
2
- {
1
+ var connected = infinispan.client(
2
+ {port: 11222, host: '127.0.0.1'},
3
+ {
3
4
  authentication: {
4
5
  enabled: true,
5
6
  saslMechanism: 'OAUTHBEARER',
@@ -1,5 +1,6 @@
1
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
2
- {
1
+ var connected = infinispan.client(
2
+ {port: 11222, host: '127.0.0.1'},
3
+ {
3
4
  authentication: {
4
5
  enabled: true,
5
6
  saslMechanism: 'PLAIN',
@@ -1,5 +1,6 @@
1
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'},
2
- {
1
+ var connected = infinispan.client(
2
+ {port: 11222, host: '127.0.0.1'},
3
+ {
3
4
  authentication: {
4
5
  enabled: true,
5
6
  saslMechanism: 'SCRAM-SHA-1',
@@ -21,7 +21,7 @@ async function test() {
21
21
  let stats = await client.stats();
22
22
  console.log('Number of stores: ' + stats.stores);
23
23
  console.log('Number of cache hits: ' + stats.hits);
24
- console.log('All stats: ' + JSON.stringify(stats, null, " "));
24
+ console.log('All statistics: ' + JSON.stringify(stats, null, " "));
25
25
 
26
26
  await client.disconnect();
27
27
  }
@@ -1,6 +1,11 @@
1
1
  var infinispan = require('infinispan');
2
2
 
3
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
3
+ var connected = infinispan.client(
4
+ {port: 11222, host: '127.0.0.1'}
5
+ {
6
+ // Configure client connections with authentication and encryption here.
7
+ }
8
+ );
4
9
 
5
10
  connected.then(function (client) {
6
11
 
@@ -18,6 +23,7 @@ connected.then(function (client) {
18
23
  var clientGetMetaForReplace = showReplace.then(
19
24
  function() { return client.getWithMetadata('cond'); });
20
25
 
26
+ // Call the getWithMetadata method to retrieve the value and its metadata.
21
27
  var clientReplaceWithVersion = clientGetMetaForReplace.then(
22
28
  function(entry) {
23
29
  console.log('getWithMetadata(cond)=' + JSON.stringify(entry));
@@ -1,7 +1,11 @@
1
1
  var infinispan = require('infinispan');
2
2
 
3
3
  var connected = infinispan.client(
4
- [{port: 11322, host: '127.0.0.1'}, {port: 11222, host: '127.0.0.1'}]);
4
+ [{port: 11322, host: '127.0.0.1'}, {port: 11222, host: '127.0.0.1'}]
5
+ {
6
+ // Configure client connections with authentication and encryption here.
7
+ }
8
+ );
5
9
 
6
10
  connected.then(function (client) {
7
11
 
@@ -1,8 +1,8 @@
1
1
  var infinispan = require('infinispan');
2
2
 
3
3
  var connected = infinispan.client(
4
- {port: 11222, host: '127.0.0.1'}
5
- , {
4
+ {port: 11222, host: '127.0.0.1'},
5
+ {
6
6
  dataFormat : {
7
7
  keyType: 'application/json',
8
8
  valueType: 'application/json'
@@ -1,6 +1,11 @@
1
1
  var infinispan = require('infinispan');
2
2
 
3
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
3
+ var connected = infinispan.client(
4
+ {port: 11222, host: '127.0.0.1'}
5
+ {
6
+ // Configure client connections with authentication and encryption here.
7
+ }
8
+ );
4
9
 
5
10
  connected.then(function (client) {
6
11
 
@@ -8,26 +13,26 @@ connected.then(function (client) {
8
13
 
9
14
  var clientGetMetaAndSize = clientPutExpiry.then(
10
15
  function() {
11
- // Compute getWithMetadata and size in parallel
16
+ // Compute getWithMetadata and size in parallel.
12
17
  return Promise.all([client.getWithMetadata('expiry'), client.size()]);
13
18
  });
14
19
 
15
20
  var showGetMetaAndSize = clientGetMetaAndSize.then(
16
21
  function(values) {
17
- console.log('before expiration:');
22
+ console.log('Before expiration:');
18
23
  console.log('getWithMetadata(expiry)=' + JSON.stringify(values[0]));
19
24
  console.log('size=' + values[1]);
20
25
  });
21
26
 
22
27
  var clientContainsAndSize = showGetMetaAndSize.then(
23
28
  function() {
24
- sleepFor(1100); // Sleep to force expiration
29
+ sleepFor(1100); // Sleep to force expiration.
25
30
  return Promise.all([client.containsKey('expiry'), client.size()]);
26
31
  });
27
32
 
28
33
  var showContainsAndSize = clientContainsAndSize.then(
29
34
  function(values) {
30
- console.log('after expiration:');
35
+ console.log('After expiration:');
31
36
  console.log('containsKey(expiry)=' + values[0]);
32
37
  console.log('size=' + values[1]);
33
38
  });
@@ -43,5 +48,5 @@ connected.then(function (client) {
43
48
 
44
49
  function sleepFor(sleepDuration){
45
50
  var now = new Date().getTime();
46
- while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
51
+ while(new Date().getTime() < now + sleepDuration){ /* Do nothing. */ }
47
52
  }
@@ -1,8 +1,20 @@
1
1
  var infinispan = require('infinispan');
2
2
 
3
3
  // Connect to {brandname} Server.
4
+ // Use an existing cache named "myCache".
4
5
  var connected = infinispan.client(
5
- {port: 11222, host: '127.0.0.1'}, {cacheName: 'myCache'});
6
+ {port: 11222, host: '127.0.0.1'},
7
+ {
8
+ cacheName: 'myCache',
9
+ clientIntelligence: 'BASIC',
10
+ authentication: {
11
+ enabled: true,
12
+ saslMechanism: 'DIGEST-MD5',
13
+ userName: 'username',
14
+ password: 'changeme'
15
+ }
16
+ }
17
+ );
6
18
 
7
19
  connected.then(function (client) {
8
20
 
@@ -11,7 +11,7 @@ var connected = infinispan.client(
11
11
  );
12
12
 
13
13
  connected.then(function (client) {
14
-
14
+ // Include the remote event converter to avoid unnecessary roundtrips.
15
15
  var opts = {
16
16
  converterFactory : {
17
17
  name: "key-value-with-previous-converter-factory"
@@ -22,9 +22,8 @@ connected.then(function (client) {
22
22
 
23
23
  var clientAddListeners = clientAddListenerCreate.then(
24
24
  function(listenerId) {
25
- // Multiple callbacks can be associated with a single client-side listener.
26
- // This is achieved by registering listeners with the same listener id
27
- // as shown in the example below.
25
+ // Associate multiple callbacks with a single client-side listener.
26
+ // To do this, register listeners with the same listener ID.
28
27
  var clientAddListenerModify =
29
28
  client.addListener('modify', logEvent("Modified"), {opts, listenerId: listenerId});
30
29
 
@@ -1,6 +1,17 @@
1
1
  var infinispan = require('infinispan');
2
2
 
3
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
3
+ var connected = infinispan.client(
4
+ {port: 11222, host: '127.0.0.1'},
5
+ {
6
+ cacheName: 'myCache',
7
+ authentication: {
8
+ enabled: true,
9
+ saslMechanism: 'DIGEST-MD5',
10
+ userName: 'username',
11
+ password: 'changeme'
12
+ }
13
+ }
14
+ );
4
15
 
5
16
  connected.then(function (client) {
6
17
  var data = [
@@ -25,7 +36,7 @@ connected.then(function (client) {
25
36
  var showIterated = clientIterator.then(
26
37
  function(it) {
27
38
  function loop(promise, fn) {
28
- // Simple recursive loop over iterator's next() call
39
+ // Simple recursive loop over the iterator's next() call.
29
40
  return promise.then(fn).then(function (entry) {
30
41
  return entry.done
31
42
  ? it.close().then(function () { return entry.value; })
@@ -1,6 +1,11 @@
1
1
  var infinispan = require('infinispan');
2
2
 
3
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
3
+ var connected = infinispan.client(
4
+ {port: 11222, host: '127.0.0.1'}
5
+ {
6
+ // Configure client connections with authentication and encryption here.
7
+ }
8
+ );
4
9
 
5
10
  connected.then(function (client) {
6
11
 
@@ -8,9 +13,8 @@ connected.then(function (client) {
8
13
 
9
14
  var clientAddListeners = clientAddListenerCreate.then(
10
15
  function(listenerId) {
11
- // Multiple callbacks can be associated with a single client-side listener.
12
- // This is achieved by registering listeners with the same listener id
13
- // as shown in the example below.
16
+ // Associate multiple callbacks with a single client-side listener.
17
+ // To do this, register listeners with the same listener ID.
14
18
  var clientAddListenerModify =
15
19
  client.addListener('modify', onModify, {listenerId: listenerId});
16
20
 
@@ -1,7 +1,12 @@
1
1
  var infinispan = require('infinispan');
2
2
  var readFile = Promise.denodeify(require('fs').readFile);
3
3
 
4
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
4
+ var connected = infinispan.client(
5
+ {port: 11222, host: '127.0.0.1'}
6
+ {
7
+ // Configure client connections with authentication and encryption here.
8
+ }
9
+ );
5
10
 
6
11
  connected.then(function (client) {
7
12
 
@@ -1,6 +1,17 @@
1
1
  var infinispan = require('infinispan');
2
2
 
3
- var connected = infinispan.client({port: 11222, host: '127.0.0.1'});
3
+ var connected = infinispan.client(
4
+ {port: 11222, host: '127.0.0.1'},
5
+ {
6
+ cacheName: 'myCache',
7
+ authentication: {
8
+ enabled: true,
9
+ saslMechanism: 'DIGEST-MD5',
10
+ userName: 'username',
11
+ password: 'changeme'
12
+ }
13
+ }
14
+ );
4
15
 
5
16
  connected.then(function (client) {
6
17
 
@@ -25,7 +36,7 @@ connected.then(function (client) {
25
36
  function(stats) {
26
37
  console.log('Number of stores: ' + stats.stores);
27
38
  console.log('Number of cache hits: ' + stats.hits);
28
- console.log('All stats: ' + JSON.stringify(stats, null, " "));
39
+ console.log('All statistics: ' + JSON.stringify(stats, null, " "));
29
40
  });
30
41
 
31
42
  return showStats.finally(
@@ -2,6 +2,14 @@
2
2
  = Configuring {brandname} connections
3
3
  Configure {hr_js} clients to connect to {brandname} Server.
4
4
 
5
+ If add multiple server addresses to the configuration, the {hr_js} client loops through them until it finds a node to which it can connect.
6
+
7
+ However, you only need to add one {brandname} Server address for the client to receive the entire cluster topology.
8
+ If the {hr_js} client connects to a single server instance that is a member of a cluster, the client gets the address information for all nodes.
9
+
10
+ Because {hr_js} clients are topology aware, if a connection to one {brandname} Server breaks, the client retries any incomplete operations on other nodes in the cluster.
11
+ Likewise, if client listener that is registered on one {brandname} Server fails or leaves the cluster, the client transparently migrates the listener registration to another node in the cluster so that it can continue receiving events.
12
+
5
13
  .Prerequisites
6
14
 
7
15
  * Install the {hr_js} client.
@@ -15,12 +23,3 @@ Configure {hr_js} clients to connect to {brandname} Server.
15
23
  ----
16
24
  include::code_examples/connection-multiple-servers.js[]
17
25
  ----
18
-
19
- The preceding configuration example includes connection details for two servers.
20
- When you add multiple server addresses to the configuration, the {hr_js} client loops through them until it finds a node to which it can connect.
21
-
22
- However, you only need to add one {brandname} Server address for the client to receive the entire cluster topology.
23
- If the {hr_js} client connects to a single server instance that is a member of a cluster, the client gets the address information for all nodes.
24
-
25
- Because {hr_js} clients are topology aware, if a connection to one {brandname} Server breaks, the client retries any incomplete operations on other nodes in the cluster.
26
- Likewise, if client listener that is registered on one {brandname} Server fails or leaves the cluster, the client transparently migrates the listener registration to another node in the cluster so that it can continue receiving events.
@@ -22,19 +22,37 @@ endif::downstream[]
22
22
  ifdef::community[]
23
23
  * Install the `infinispan` client as follows:
24
24
  +
25
- [source,bash,options="nowrap",subs=attributes+]
25
+ [source,options="nowrap",subs=attributes+]
26
26
  ----
27
- $ npm i infinispan
27
+ npm install infinispan
28
28
  ----
29
29
  endif::community[]
30
30
 
31
31
  //Downstream content
32
- ifdef::downstream[]
32
+ ifdef::rhdg-install-npmrepo[]
33
+ . Add the Red Hat repository to your NPM configuration.
34
+ +
35
+ You can use the `npm config` command or add the following to an `.npmrc` file in your project:
36
+ +
37
+ [source,options="nowrap",subs=attributes+]
38
+ ----
39
+ @redhat:registry=https://npm.registry.redhat.com
40
+ registry=https://registry.npmjs.org/
41
+ ----
42
+
43
+ . Install the {hr_js} client as follows:
44
+ +
45
+ [source,options="nowrap",subs=attributes+]
46
+ ----
47
+ npm install @redhat/infinispan
48
+ ----
49
+ endif::rhdg-install-npmrepo[]
50
+ ifdef::rhdg-install-package[]
33
51
  . Download and extract the `redhat-datagrid-<version>-nodejs-client.zip` from the {portal}.
34
52
  . Install the `tgz` package from the extracted directory as in the following example:
35
53
  +
36
54
  [source,bash,options="nowrap",subs=attributes+]
37
55
  ----
38
- $ npm install /path/to/redhat-datagrid-<version>-nodejs-client/infinispan-<version>.tgz
56
+ npm install /path/to/redhat-datagrid-<version>-nodejs-client/infinispan-<version>.tgz
39
57
  ----
40
- endif::downstream[]
58
+ endif::rhdg-install-package[]
@@ -0,0 +1,116 @@
1
+ [id='client-usage_{context}']
2
+ = {hr_js} client examples
3
+
4
+ After you install and configure your {hr_js} client, start using it by trying out some basic cache operations before moving on to more complex interactions with {brandname}.
5
+
6
+ == Hello world
7
+
8
+ Create a cache named "myCache" on {brandname} Server then add and retrieve an entry.
9
+
10
+ [source,javascript,options="nowrap",subs=attributes+]
11
+ ----
12
+ include::code_examples/hello-world.js[]
13
+ ----
14
+
15
+ == Working with entries and retrieving cache statistics
16
+
17
+ Add, retrieve, remove single entries and view statistics for the cache.
18
+
19
+ [source,javascript,options="nowrap",subs=attributes+]
20
+ ----
21
+ include::code_examples/single-entries.js[]
22
+ ----
23
+
24
+ == Working with multiple cache entries
25
+
26
+ Create multiple cache entries with simple recursive loops.
27
+
28
+ [source,javascript,options="nowrap",subs=attributes+]
29
+ ----
30
+ include::code_examples/multiple-entries.js[]
31
+ ----
32
+
33
+ == Using Async and Await constructs
34
+
35
+ Node.js provides `async` and `await` constructs that can simplify cache operations.
36
+
37
+ .Single cache entries
38
+ [source,javascript,options="nowrap",subs=attributes+]
39
+ ----
40
+ include::code_examples/await-single-entries.js[]
41
+ ----
42
+
43
+ .Multiple cache entries
44
+ [source,javascript,options="nowrap",subs=attributes+]
45
+ ----
46
+ include::code_examples/await-multiple-entries.js[]
47
+ ----
48
+
49
+ == Running server-side scripts
50
+
51
+ You can add custom scripts to {brandname} Server and then run them from {hr_js} clients.
52
+
53
+ .Sample script
54
+ [source,javascript,options="nowrap",subs=attributes+]
55
+ ----
56
+ include::code_examples/sample-script.js[]
57
+ ----
58
+
59
+ .Script execution
60
+ [source,javascript,options="nowrap",subs=attributes+]
61
+ ----
62
+ include::code_examples/sample-script-execute.js[]
63
+ ----
64
+
65
+ == Registering event listeners
66
+
67
+ Event listeners notify {hr_js} clients when cache updates occur, including when entries are created, modified, removed, or expired.
68
+
69
+ [NOTE]
70
+ ====
71
+ Events for entry creation and modification notify clients about keys and values.
72
+ Events for entry removal and expiration notify clients about keys only.
73
+ ====
74
+
75
+ .Event listener registration
76
+ [source,javascript,options="nowrap",subs=attributes+]
77
+ ----
78
+ include::code_examples/register-event-listener.js[]
79
+ ----
80
+
81
+ You can tune notifications from event listeners to avoid unnecessary roundtrips with the `key-value-with-previous-converter-factory` converter.
82
+ This allows you to, for example, find out values associated with keys within the event instead of retrieving them afterwards.
83
+
84
+ .Remote event converter
85
+ [source,javascript,options="nowrap",subs=attributes+]
86
+ ----
87
+ include::code_examples/key-value-converter.js[]
88
+ ----
89
+
90
+ [TIP]
91
+ ====
92
+ You can add custom converters to {brandname} Server.
93
+ See the link:{doc_home}[{brandname} documentation] for information.
94
+ ====
95
+
96
+ == Using conditional operations
97
+
98
+ The Hot Rod protocol stores metadata about values in {brandname}.
99
+ This metadata provides a deterministic factor that lets you perform cache operations for certain conditions.
100
+ For example, if you want to replace the value of a key if the versions do not match.
101
+
102
+ Use the `getWithMetadata` method to retrieve metadata associated with the value for a key.
103
+
104
+ [source,javascript,options="nowrap",subs=attributes+]
105
+ ----
106
+ include::code_examples/conditional-operations.js[]
107
+ ----
108
+
109
+ == Working with ephemeral data
110
+
111
+ Use the `getWithMetadata` and `size` methods expire cache entries.
112
+
113
+ [source,javascript,options="nowrap",subs=attributes+]
114
+ ----
115
+ include::code_examples/ephemeral-data.js[]
116
+ ----