diff --git a/Backend Development/service-behavior/auth/index.html b/Backend Development/service-behavior/auth/index.html index bd25bcc9..f2a76bb4 100644 --- a/Backend Development/service-behavior/auth/index.html +++ b/Backend Development/service-behavior/auth/index.html @@ -4474,7 +4474,7 @@

Starting the - January 24, 2024 + January 26, 2024 @@ -4484,7 +4484,7 @@

Starting the - January 24, 2024 + January 26, 2024 diff --git a/Backend Development/service-behavior/config/index.html b/Backend Development/service-behavior/config/index.html index 6e5d43ad..c8926a9f 100644 --- a/Backend Development/service-behavior/config/index.html +++ b/Backend Development/service-behavior/config/index.html @@ -4466,7 +4466,7 @@

CLI arguments overwrite e - January 24, 2024 + January 26, 2024 @@ -4476,7 +4476,7 @@

CLI arguments overwrite e - January 24, 2024 + January 26, 2024 diff --git a/Backend Development/service-behavior/dev-mode/index.html b/Backend Development/service-behavior/dev-mode/index.html index dd82b237..ae58dab2 100644 --- a/Backend Development/service-behavior/dev-mode/index.html +++ b/Backend Development/service-behavior/dev-mode/index.html @@ -4418,7 +4418,7 @@

Any custom conf - January 24, 2024 + January 26, 2024 @@ -4428,7 +4428,7 @@

Any custom conf - January 24, 2024 + January 26, 2024 diff --git a/Backend Development/service-behavior/index.html b/Backend Development/service-behavior/index.html index a972daa5..a8d2a735 100644 --- a/Backend Development/service-behavior/index.html +++ b/Backend Development/service-behavior/index.html @@ -4355,7 +4355,7 @@

Documentation - January 24, 2024 + January 26, 2024 @@ -4365,7 +4365,7 @@

Documentation - January 24, 2024 + January 26, 2024 diff --git a/Backend Development/service-behavior/nats/index.html b/Backend Development/service-behavior/nats/index.html index 4b37eb1f..1f122f0e 100644 --- a/Backend Development/service-behavior/nats/index.html +++ b/Backend Development/service-behavior/nats/index.html @@ -4414,7 +4414,7 @@

The developer disables the - January 24, 2024 + January 26, 2024 @@ -4424,7 +4424,7 @@

The developer disables the - January 24, 2024 + January 26, 2024 diff --git a/Backend Development/service-behavior/service/index.html b/Backend Development/service-behavior/service/index.html index a74a5f91..938bfe1f 100644 --- a/Backend Development/service-behavior/service/index.html +++ b/Backend Development/service-behavior/service/index.html @@ -4389,7 +4389,7 @@

Starting a service - January 24, 2024 + January 26, 2024 @@ -4399,7 +4399,7 @@

Starting a service - January 24, 2024 + January 26, 2024 diff --git a/Backend Development/typescript/e2e-log-service/index.html b/Backend Development/typescript/e2e-log-service/index.html index 85dd7443..56649376 100644 --- a/Backend Development/typescript/e2e-log-service/index.html +++ b/Backend Development/typescript/e2e-log-service/index.html @@ -4407,6 +4407,7 @@

Steps&

First, we need to import the startService function from our library (lib.ts) and the encode function from the standard Deno library.

import { startService } from "https://deno.land/x/telestion/mod.ts";
 import { encode } from "https://deno.land/std@0.186.0/encoding/hex.ts";
+import { resolve } from "https://deno.land/std@0.186.0/path/mod.ts";
 
  • @@ -4416,65 +4417,75 @@

    Steps&

  • We then call the startService function to set up our service. This will return an object containing information about the message bus that we can use to subscribe to messages.

    -
    const { messageBus } = await startService();
    +
    const { messageBus, dataDir } = await startService();
    +
    +
  • +
  • +

    We then resolve the log file path and create its parent directory if it doesn’t exist yet.

    +
    const logFilePath = resolve(dataDir, "log.txt");
    +await Deno.mkdir(dataDir, { recursive: true });
     
  • We then subscribe to the message bus, using a wildcard subscription for any messages published on the log.> subject. This will allow us to receive all messages published on any topics starting with log..

    -
    const logMessages = messageBus.subscribe("log.>");
    +
    const logMessages = messageBus.subscribe("log.>");
     
  • We use a for-await-of loop to receive messages from the message bus. For each message, we extract the subject (split the string on ., then take the second element) and the message data, which we encode using the encode function from the standard library.

    -
    for await (const msg of logMessages) {
    -  try {
    -    const currentTime = new Date().toISOString();
    -    const logMessage = encode(msg.data).toString();
    -    const subject = msg.subject.split(".")[1];
    +
    for await (const msg of logMessages) {
    +  try {
    +    const currentTime = new Date().toISOString();
    +    const logMessage = encode(msg.data).toString();
    +    const subject = msg.subject.split(".")[1];
     
  • We log the message to the console and write it to a file (appending it to the end).

    -
        console.log(`${currentTime} [${subject}] ${logMessage}`);
    -    await Deno.writeFile(
    -      "log.txt",
    -      encoder.encode(`${currentTime} [${subject}] ${logMessage}\n`),
    -      { append: true },
    -    );
    -  } catch (error) {
    -    console.error(error);
    -  }
    -}
    +
        console.log(`${currentTime} [${subject}] ${logMessage}`);
    +    await Deno.writeFile(
    +      logFilePath,
    +      encoder.encode(`${currentTime} [${subject}] ${logMessage}\n`),
    +      { append: true },
    +    );
    +  } catch (error) {
    +    console.error(error);
    +  }
    +}
     
  • And that’s it! Our service is now complete and ready to be used.

    Final Code

    -
    import { startService } from "https://deno.land/x/telestion/mod.ts";
    -import { encode } from "https://deno.land/std@0.186.0/encoding/hex.ts";
    -
    -const encoder = new TextEncoder();
    -
    -const { messageBus } = await startService();
    -
    -const logMessages = messageBus.subscribe("log.>");
    -
    -for await (const msg of logMessages) {
    -  try {
    -    const currentTime = new Date().toISOString();
    -    const logMessage = encode(msg.data).toString();
    -    const subject = msg.subject.split(".")[1];
    -
    -    console.log(`${currentTime} [${subject}] ${logMessage}`);
    -    await Deno.writeFile(
    -      "log.txt",
    -      encoder.encode(`${currentTime} [${subject}] ${logMessage}\n`),
    -      { append: true },
    -    );
    -  } catch (error) {
    -    console.error(error);
    -  }
    -}
    +
    import { startService } from "https://deno.land/x/telestion/mod.ts";
    +import { encode } from "https://deno.land/std@0.186.0/encoding/hex.ts";
    +import { resolve } from "https://deno.land/std/0.186.0/path/mod.ts";
    +
    +const encoder = new TextEncoder();
    +
    +const { messageBus, dataDir } = await startService();
    +
    +const logFilePath = resolve(dataDir, "log.txt");
    +await Deno.mkdir(dataDir, { recursive: true });
    +
    +const logMessages = messageBus.subscribe("log.>");
    +
    +for await (const msg of logMessages) {
    +  try {
    +    const currentTime = new Date().toISOString();
    +    const logMessage = encode(msg.data).toString();
    +    const subject = msg.subject.split(".")[1];
    +
    +    console.log(`${currentTime} [${subject}] ${logMessage}`);
    +    await Deno.writeFile(
    +      logFilePath,
    +      encoder.encode(`${currentTime} [${subject}] ${logMessage}\n`),
    +      { append: true },
    +    );
    +  } catch (error) {
    +    console.error(error);
    +  }
    +}
     
    @@ -4498,7 +4509,7 @@

    Final Code - December 15, 2023 + January 26, 2024 diff --git a/Frontend Development/api/application/functions/initTelestion/index.html b/Frontend Development/api/application/functions/initTelestion/index.html index 7330d850..6353a48f 100644 --- a/Frontend Development/api/application/functions/initTelestion/index.html +++ b/Frontend Development/api/application/functions/initTelestion/index.html @@ -4407,7 +4407,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4417,7 +4417,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/application/index.html b/Frontend Development/api/application/index.html index 1ca20662..7a97274b 100644 --- a/Frontend Development/api/application/index.html +++ b/Frontend Development/api/application/index.html @@ -4395,7 +4395,7 @@

    useWidgetConfig - January 24, 2024 + January 26, 2024 @@ -4405,7 +4405,7 @@

    useWidgetConfig - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/classes/LoginError/index.html b/Frontend Development/api/auth/classes/LoginError/index.html index de7d7239..c733388c 100644 --- a/Frontend Development/api/auth/classes/LoginError/index.html +++ b/Frontend Development/api/auth/classes/LoginError/index.html @@ -5025,7 +5025,7 @@

    Inherited from - January 24, 2024 + January 26, 2024 @@ -5035,7 +5035,7 @@

    Inherited from - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/functions/attemptAutoLogin/index.html b/Frontend Development/api/auth/functions/attemptAutoLogin/index.html index 2a3aa994..b8c8a3c3 100644 --- a/Frontend Development/api/auth/functions/attemptAutoLogin/index.html +++ b/Frontend Development/api/auth/functions/attemptAutoLogin/index.html @@ -4390,7 +4390,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4400,7 +4400,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/functions/getNatsConnection/index.html b/Frontend Development/api/auth/functions/getNatsConnection/index.html index 27fcb829..53e6a7d2 100644 --- a/Frontend Development/api/auth/functions/getNatsConnection/index.html +++ b/Frontend Development/api/auth/functions/getNatsConnection/index.html @@ -4384,7 +4384,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4394,7 +4394,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/functions/getUser/index.html b/Frontend Development/api/auth/functions/getUser/index.html index 3a87746d..6826ec87 100644 --- a/Frontend Development/api/auth/functions/getUser/index.html +++ b/Frontend Development/api/auth/functions/getUser/index.html @@ -4385,7 +4385,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4395,7 +4395,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/functions/isLoggedIn/index.html b/Frontend Development/api/auth/functions/isLoggedIn/index.html index b1f33594..b50b9a63 100644 --- a/Frontend Development/api/auth/functions/isLoggedIn/index.html +++ b/Frontend Development/api/auth/functions/isLoggedIn/index.html @@ -4386,7 +4386,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4396,7 +4396,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/functions/login/index.html b/Frontend Development/api/auth/functions/login/index.html index 9c1c1df2..02c63079 100644 --- a/Frontend Development/api/auth/functions/login/index.html +++ b/Frontend Development/api/auth/functions/login/index.html @@ -4432,7 +4432,7 @@

    Throws - January 24, 2024 + January 26, 2024 @@ -4442,7 +4442,7 @@

    Throws - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/functions/logout/index.html b/Frontend Development/api/auth/functions/logout/index.html index ae658ab0..7d771e12 100644 --- a/Frontend Development/api/auth/functions/logout/index.html +++ b/Frontend Development/api/auth/functions/logout/index.html @@ -4386,7 +4386,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4396,7 +4396,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/functions/setAutoLoginCredentials/index.html b/Frontend Development/api/auth/functions/setAutoLoginCredentials/index.html index c8e65246..4449975d 100644 --- a/Frontend Development/api/auth/functions/setAutoLoginCredentials/index.html +++ b/Frontend Development/api/auth/functions/setAutoLoginCredentials/index.html @@ -4456,7 +4456,7 @@

    Deprecated - January 24, 2024 + January 26, 2024 @@ -4466,7 +4466,7 @@

    Deprecated - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/functions/setNatsConnection/index.html b/Frontend Development/api/auth/functions/setNatsConnection/index.html index 2a454ad9..c5d386c8 100644 --- a/Frontend Development/api/auth/functions/setNatsConnection/index.html +++ b/Frontend Development/api/auth/functions/setNatsConnection/index.html @@ -4404,7 +4404,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4414,7 +4414,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/functions/setUser/index.html b/Frontend Development/api/auth/functions/setUser/index.html index 14c0e80d..c313fe97 100644 --- a/Frontend Development/api/auth/functions/setUser/index.html +++ b/Frontend Development/api/auth/functions/setUser/index.html @@ -4406,7 +4406,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4416,7 +4416,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/functions/useNatsSubscription/index.html b/Frontend Development/api/auth/functions/useNatsSubscription/index.html index dd4219c1..c0f1a352 100644 --- a/Frontend Development/api/auth/functions/useNatsSubscription/index.html +++ b/Frontend Development/api/auth/functions/useNatsSubscription/index.html @@ -4406,7 +4406,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4416,7 +4416,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/index.html b/Frontend Development/api/auth/index.html index 39c2fe01..e50d38b5 100644 --- a/Frontend Development/api/auth/index.html +++ b/Frontend Development/api/auth/index.html @@ -4416,7 +4416,7 @@

    useNats - January 24, 2024 + January 26, 2024 @@ -4426,7 +4426,7 @@

    useNats - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/interfaces/ErrorMessages/index.html b/Frontend Development/api/auth/interfaces/ErrorMessages/index.html index 02d0cb22..b6c78bc4 100644 --- a/Frontend Development/api/auth/interfaces/ErrorMessages/index.html +++ b/Frontend Development/api/auth/interfaces/ErrorMessages/index.html @@ -4460,7 +4460,7 @@

    usernameMessage? - January 24, 2024 + January 26, 2024 @@ -4470,7 +4470,7 @@

    usernameMessage? - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/auth/interfaces/User/index.html b/Frontend Development/api/auth/interfaces/User/index.html index 97843e14..43b47e98 100644 --- a/Frontend Development/api/auth/interfaces/User/index.html +++ b/Frontend Development/api/auth/interfaces/User/index.html @@ -4440,7 +4440,7 @@

    username - January 24, 2024 + January 26, 2024 @@ -4450,7 +4450,7 @@

    username - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/index.html b/Frontend Development/api/index.html index ab2f8391..e7b8ceda 100644 --- a/Frontend Development/api/index.html +++ b/Frontend Development/api/index.html @@ -4343,7 +4343,7 @@

    Modules - January 24, 2024 + January 26, 2024 @@ -4353,7 +4353,7 @@

    Modules - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/index/functions/JSONCodec/index.html b/Frontend Development/api/index/functions/JSONCodec/index.html index 5ecf7f90..6a8a1a8c 100644 --- a/Frontend Development/api/index/functions/JSONCodec/index.html +++ b/Frontend Development/api/index/functions/JSONCodec/index.html @@ -4427,7 +4427,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4437,7 +4437,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/index/functions/registerWidgets/index.html b/Frontend Development/api/index/functions/registerWidgets/index.html index b47ec069..5fa0a78d 100644 --- a/Frontend Development/api/index/functions/registerWidgets/index.html +++ b/Frontend Development/api/index/functions/registerWidgets/index.html @@ -4407,7 +4407,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4417,7 +4417,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/index/functions/useNats/index.html b/Frontend Development/api/index/functions/useNats/index.html index f16704e9..a80c3096 100644 --- a/Frontend Development/api/index/functions/useNats/index.html +++ b/Frontend Development/api/index/functions/useNats/index.html @@ -4384,7 +4384,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4394,7 +4394,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/index/functions/useWidgetConfig/index.html b/Frontend Development/api/index/functions/useWidgetConfig/index.html index 01b0fc58..cea096f4 100644 --- a/Frontend Development/api/index/functions/useWidgetConfig/index.html +++ b/Frontend Development/api/index/functions/useWidgetConfig/index.html @@ -4427,7 +4427,7 @@

    Throws - January 24, 2024 + January 26, 2024 @@ -4437,7 +4437,7 @@

    Throws - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/index/index.html b/Frontend Development/api/index/index.html index 135febfa..1aacf7ec 100644 --- a/Frontend Development/api/index/index.html +++ b/Frontend Development/api/index/index.html @@ -4417,7 +4417,7 @@

    initTelestion - January 24, 2024 + January 26, 2024 @@ -4427,7 +4427,7 @@

    initTelestion - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/index/interfaces/TelestionOptions/index.html b/Frontend Development/api/index/interfaces/TelestionOptions/index.html index f87aaa6c..b3fcd44d 100644 --- a/Frontend Development/api/index/interfaces/TelestionOptions/index.html +++ b/Frontend Development/api/index/interfaces/TelestionOptions/index.html @@ -4600,7 +4600,7 @@

    widgets? - January 24, 2024 + January 26, 2024 @@ -4610,7 +4610,7 @@

    widgets? - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/index/interfaces/Widget/index.html b/Frontend Development/api/index/interfaces/Widget/index.html index 17380db1..6061a0f4 100644 --- a/Frontend Development/api/index/interfaces/Widget/index.html +++ b/Frontend Development/api/index/interfaces/Widget/index.html @@ -4640,7 +4640,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4650,7 +4650,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/index/type-aliases/UserData/index.html b/Frontend Development/api/index/type-aliases/UserData/index.html index 7ca6ccd3..2e226ada 100644 --- a/Frontend Development/api/index/type-aliases/UserData/index.html +++ b/Frontend Development/api/index/type-aliases/UserData/index.html @@ -4485,7 +4485,7 @@

    widgetInstances - January 24, 2024 + January 26, 2024 @@ -4495,7 +4495,7 @@

    widgetInstances - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/classes/NatsError/index.html b/Frontend Development/api/nats/classes/NatsError/index.html index e4066658..b4d87bb5 100644 --- a/Frontend Development/api/nats/classes/NatsError/index.html +++ b/Frontend Development/api/nats/classes/NatsError/index.html @@ -5609,7 +5609,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -5619,7 +5619,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/functions/StringCodec/index.html b/Frontend Development/api/nats/functions/StringCodec/index.html index 446e041a..e703180c 100644 --- a/Frontend Development/api/nats/functions/StringCodec/index.html +++ b/Frontend Development/api/nats/functions/StringCodec/index.html @@ -4386,7 +4386,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4396,7 +4396,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/functions/headers/index.html b/Frontend Development/api/nats/functions/headers/index.html index 3b433d28..4fda5c5c 100644 --- a/Frontend Development/api/nats/functions/headers/index.html +++ b/Frontend Development/api/nats/functions/headers/index.html @@ -4405,7 +4405,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4415,7 +4415,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/index.html b/Frontend Development/api/nats/index.html index 82cd023f..15b84064 100644 --- a/Frontend Development/api/nats/index.html +++ b/Frontend Development/api/nats/index.html @@ -4441,7 +4441,7 @@

    JSONCodec - January 24, 2024 + January 26, 2024 @@ -4451,7 +4451,7 @@

    JSONCodec - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/interfaces/Codec/index.html b/Frontend Development/api/nats/interfaces/Codec/index.html index 21745aae..a67020c9 100644 --- a/Frontend Development/api/nats/interfaces/Codec/index.html +++ b/Frontend Development/api/nats/interfaces/Codec/index.html @@ -4563,7 +4563,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4573,7 +4573,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/interfaces/Msg/index.html b/Frontend Development/api/nats/interfaces/Msg/index.html index 1bae3f2e..d046eb90 100644 --- a/Frontend Development/api/nats/interfaces/Msg/index.html +++ b/Frontend Development/api/nats/interfaces/Msg/index.html @@ -4777,7 +4777,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4787,7 +4787,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/interfaces/MsgHdrs/index.html b/Frontend Development/api/nats/interfaces/MsgHdrs/index.html index 7791c340..84cddee5 100644 --- a/Frontend Development/api/nats/interfaces/MsgHdrs/index.html +++ b/Frontend Development/api/nats/interfaces/MsgHdrs/index.html @@ -5199,7 +5199,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -5209,7 +5209,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/interfaces/NatsConnection/index.html b/Frontend Development/api/nats/interfaces/NatsConnection/index.html index 0309ff4e..a1c42c26 100644 --- a/Frontend Development/api/nats/interfaces/NatsConnection/index.html +++ b/Frontend Development/api/nats/interfaces/NatsConnection/index.html @@ -5592,7 +5592,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -5602,7 +5602,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/interfaces/PublishOptions/index.html b/Frontend Development/api/nats/interfaces/PublishOptions/index.html index c61fbcf7..94aa5757 100644 --- a/Frontend Development/api/nats/interfaces/PublishOptions/index.html +++ b/Frontend Development/api/nats/interfaces/PublishOptions/index.html @@ -4441,7 +4441,7 @@

    reply? - January 24, 2024 + January 26, 2024 @@ -4451,7 +4451,7 @@

    reply? - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/interfaces/RequestOptions/index.html b/Frontend Development/api/nats/interfaces/RequestOptions/index.html index 71f35b18..4dae073d 100644 --- a/Frontend Development/api/nats/interfaces/RequestOptions/index.html +++ b/Frontend Development/api/nats/interfaces/RequestOptions/index.html @@ -4489,7 +4489,7 @@

    timeout - January 24, 2024 + January 26, 2024 @@ -4499,7 +4499,7 @@

    timeout - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/interfaces/Sub/index.html b/Frontend Development/api/nats/interfaces/Sub/index.html index f984e4ac..cc44438f 100644 --- a/Frontend Development/api/nats/interfaces/Sub/index.html +++ b/Frontend Development/api/nats/interfaces/Sub/index.html @@ -5093,7 +5093,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -5103,7 +5103,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/interfaces/SubOpts/index.html b/Frontend Development/api/nats/interfaces/SubOpts/index.html index c7416ca6..b1a73521 100644 --- a/Frontend Development/api/nats/interfaces/SubOpts/index.html +++ b/Frontend Development/api/nats/interfaces/SubOpts/index.html @@ -4567,7 +4567,7 @@

    timeout? - January 24, 2024 + January 26, 2024 @@ -4577,7 +4577,7 @@

    timeout? - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/type-aliases/MsgRequest/index.html b/Frontend Development/api/nats/type-aliases/MsgRequest/index.html index cf4e2a4b..eb227d7e 100644 --- a/Frontend Development/api/nats/type-aliases/MsgRequest/index.html +++ b/Frontend Development/api/nats/type-aliases/MsgRequest/index.html @@ -4323,7 +4323,7 @@

    MsgRequest

    - January 24, 2024 + January 26, 2024 @@ -4333,7 +4333,7 @@

    MsgRequest

    - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/type-aliases/Subscription/index.html b/Frontend Development/api/nats/type-aliases/Subscription/index.html index 75cb194b..61eec211 100644 --- a/Frontend Development/api/nats/type-aliases/Subscription/index.html +++ b/Frontend Development/api/nats/type-aliases/Subscription/index.html @@ -4324,7 +4324,7 @@

    Subscription

    - January 24, 2024 + January 26, 2024 @@ -4334,7 +4334,7 @@

    Subscription

    - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/nats/type-aliases/SubscriptionOptions/index.html b/Frontend Development/api/nats/type-aliases/SubscriptionOptions/index.html index 3e10a12d..189700db 100644 --- a/Frontend Development/api/nats/type-aliases/SubscriptionOptions/index.html +++ b/Frontend Development/api/nats/type-aliases/SubscriptionOptions/index.html @@ -4324,7 +4324,7 @@

    SubscriptionOptions

    - January 24, 2024 + January 26, 2024 @@ -4334,7 +4334,7 @@

    SubscriptionOptions

    - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/functions/getBlankUserData/index.html b/Frontend Development/api/user-data/functions/getBlankUserData/index.html index 58ec6fc9..498d5d6e 100644 --- a/Frontend Development/api/user-data/functions/getBlankUserData/index.html +++ b/Frontend Development/api/user-data/functions/getBlankUserData/index.html @@ -4406,7 +4406,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4416,7 +4416,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/functions/getEmptyDashboard/index.html b/Frontend Development/api/user-data/functions/getEmptyDashboard/index.html index 04da15f0..7126fec2 100644 --- a/Frontend Development/api/user-data/functions/getEmptyDashboard/index.html +++ b/Frontend Development/api/user-data/functions/getEmptyDashboard/index.html @@ -4385,7 +4385,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4395,7 +4395,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/functions/getUserData/index.html b/Frontend Development/api/user-data/functions/getUserData/index.html index 58974838..0fcc3e99 100644 --- a/Frontend Development/api/user-data/functions/getUserData/index.html +++ b/Frontend Development/api/user-data/functions/getUserData/index.html @@ -4386,7 +4386,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4396,7 +4396,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/functions/removeUserData/index.html b/Frontend Development/api/user-data/functions/removeUserData/index.html index d046db71..fd9917b6 100644 --- a/Frontend Development/api/user-data/functions/removeUserData/index.html +++ b/Frontend Development/api/user-data/functions/removeUserData/index.html @@ -4385,7 +4385,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4395,7 +4395,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/functions/setUserData/index.html b/Frontend Development/api/user-data/functions/setUserData/index.html index 65485c07..041bf27a 100644 --- a/Frontend Development/api/user-data/functions/setUserData/index.html +++ b/Frontend Development/api/user-data/functions/setUserData/index.html @@ -4412,7 +4412,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4422,7 +4422,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/index.html b/Frontend Development/api/user-data/index.html index e7b6edb0..ef523eef 100644 --- a/Frontend Development/api/user-data/index.html +++ b/Frontend Development/api/user-data/index.html @@ -4414,7 +4414,7 @@

    UserData - January 24, 2024 + January 26, 2024 @@ -4424,7 +4424,7 @@

    UserData - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/type-aliases/Dashboard/index.html b/Frontend Development/api/user-data/type-aliases/Dashboard/index.html index 2082444c..de11e934 100644 --- a/Frontend Development/api/user-data/type-aliases/Dashboard/index.html +++ b/Frontend Development/api/user-data/type-aliases/Dashboard/index.html @@ -4462,7 +4462,7 @@

    title& - January 24, 2024 + January 26, 2024 @@ -4472,7 +4472,7 @@

    title& - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/type-aliases/WidgetInstance/index.html b/Frontend Development/api/user-data/type-aliases/WidgetInstance/index.html index b2fe9fa2..a45364b2 100644 --- a/Frontend Development/api/user-data/type-aliases/WidgetInstance/index.html +++ b/Frontend Development/api/user-data/type-aliases/WidgetInstance/index.html @@ -4495,7 +4495,7 @@

    See&pa - January 24, 2024 + January 26, 2024 @@ -4505,7 +4505,7 @@

    See&pa - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/variables/dashboardSchema/index.html b/Frontend Development/api/user-data/variables/dashboardSchema/index.html index 793f3dac..cee8857a 100644 --- a/Frontend Development/api/user-data/variables/dashboardSchema/index.html +++ b/Frontend Development/api/user-data/variables/dashboardSchema/index.html @@ -4324,7 +4324,7 @@

    dashboardSchema

    - January 24, 2024 + January 26, 2024 @@ -4334,7 +4334,7 @@

    dashboardSchema

    - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/variables/idSchema/index.html b/Frontend Development/api/user-data/variables/idSchema/index.html index 7571658d..c94b23b9 100644 --- a/Frontend Development/api/user-data/variables/idSchema/index.html +++ b/Frontend Development/api/user-data/variables/idSchema/index.html @@ -4386,7 +4386,7 @@

    See¶< - January 24, 2024 + January 26, 2024 @@ -4396,7 +4396,7 @@

    See¶< - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/variables/layoutSchema/index.html b/Frontend Development/api/user-data/variables/layoutSchema/index.html index 77daf505..703daee3 100644 --- a/Frontend Development/api/user-data/variables/layoutSchema/index.html +++ b/Frontend Development/api/user-data/variables/layoutSchema/index.html @@ -4324,7 +4324,7 @@

    layoutSchema

    - January 24, 2024 + January 26, 2024 @@ -4334,7 +4334,7 @@

    layoutSchema

    - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/variables/semverRegExp/index.html b/Frontend Development/api/user-data/variables/semverRegExp/index.html index 4a12f4ff..169af71f 100644 --- a/Frontend Development/api/user-data/variables/semverRegExp/index.html +++ b/Frontend Development/api/user-data/variables/semverRegExp/index.html @@ -4325,7 +4325,7 @@

    semverRegExp

    - January 24, 2024 + January 26, 2024 @@ -4335,7 +4335,7 @@

    semverRegExp

    - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/variables/userDataSchema/index.html b/Frontend Development/api/user-data/variables/userDataSchema/index.html index c9b1917a..a37fb7a3 100644 --- a/Frontend Development/api/user-data/variables/userDataSchema/index.html +++ b/Frontend Development/api/user-data/variables/userDataSchema/index.html @@ -4385,7 +4385,7 @@

    See¶< - January 24, 2024 + January 26, 2024 @@ -4395,7 +4395,7 @@

    See¶< - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/user-data/variables/widgetInstanceSchema/index.html b/Frontend Development/api/user-data/variables/widgetInstanceSchema/index.html index 93933b0b..cddb65ca 100644 --- a/Frontend Development/api/user-data/variables/widgetInstanceSchema/index.html +++ b/Frontend Development/api/user-data/variables/widgetInstanceSchema/index.html @@ -4385,7 +4385,7 @@

    See¶< - January 24, 2024 + January 26, 2024 @@ -4395,7 +4395,7 @@

    See¶< - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/utils/functions/generateDashboardId/index.html b/Frontend Development/api/utils/functions/generateDashboardId/index.html index 5b8b398e..54ded27e 100644 --- a/Frontend Development/api/utils/functions/generateDashboardId/index.html +++ b/Frontend Development/api/utils/functions/generateDashboardId/index.html @@ -4386,7 +4386,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4396,7 +4396,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/utils/functions/isUserDataUpToDate/index.html b/Frontend Development/api/utils/functions/isUserDataUpToDate/index.html index 0aa5f2e9..22b927e3 100644 --- a/Frontend Development/api/utils/functions/isUserDataUpToDate/index.html +++ b/Frontend Development/api/utils/functions/isUserDataUpToDate/index.html @@ -4408,7 +4408,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4418,7 +4418,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/utils/functions/loadFileContents/index.html b/Frontend Development/api/utils/functions/loadFileContents/index.html index 8ecc38a7..930715eb 100644 --- a/Frontend Development/api/utils/functions/loadFileContents/index.html +++ b/Frontend Development/api/utils/functions/loadFileContents/index.html @@ -4412,7 +4412,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4422,7 +4422,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/utils/functions/wait/index.html b/Frontend Development/api/utils/functions/wait/index.html index eaf1e3a8..b49f547a 100644 --- a/Frontend Development/api/utils/functions/wait/index.html +++ b/Frontend Development/api/utils/functions/wait/index.html @@ -4407,7 +4407,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4417,7 +4417,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/utils/index.html b/Frontend Development/api/utils/index.html index b168d642..f332bdff 100644 --- a/Frontend Development/api/utils/index.html +++ b/Frontend Development/api/utils/index.html @@ -4370,7 +4370,7 @@

    Functions - January 24, 2024 + January 26, 2024 @@ -4380,7 +4380,7 @@

    Functions - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/widget/functions/WidgetRenderer/index.html b/Frontend Development/api/widget/functions/WidgetRenderer/index.html index 7eb6c549..bd48757a 100644 --- a/Frontend Development/api/widget/functions/WidgetRenderer/index.html +++ b/Frontend Development/api/widget/functions/WidgetRenderer/index.html @@ -4427,7 +4427,7 @@

    Throws - January 24, 2024 + January 26, 2024 @@ -4437,7 +4437,7 @@

    Throws - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/widget/functions/getWidgetById/index.html b/Frontend Development/api/widget/functions/getWidgetById/index.html index 20988cea..5592b8dd 100644 --- a/Frontend Development/api/widget/functions/getWidgetById/index.html +++ b/Frontend Development/api/widget/functions/getWidgetById/index.html @@ -4407,7 +4407,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4417,7 +4417,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/widget/functions/getWidgets/index.html b/Frontend Development/api/widget/functions/getWidgets/index.html index 0cef10cc..d84278ae 100644 --- a/Frontend Development/api/widget/functions/getWidgets/index.html +++ b/Frontend Development/api/widget/functions/getWidgets/index.html @@ -4386,7 +4386,7 @@

    Returns - January 24, 2024 + January 26, 2024 @@ -4396,7 +4396,7 @@

    Returns - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/widget/index.html b/Frontend Development/api/widget/index.html index 297363d4..264b81d5 100644 --- a/Frontend Development/api/widget/index.html +++ b/Frontend Development/api/widget/index.html @@ -4418,7 +4418,7 @@

    registerWidgets - January 24, 2024 + January 26, 2024 @@ -4428,7 +4428,7 @@

    registerWidgets - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/widget/interfaces/WidgetRendererProps/index.html b/Frontend Development/api/widget/interfaces/WidgetRendererProps/index.html index 50a17224..d0d678f5 100644 --- a/Frontend Development/api/widget/interfaces/WidgetRendererProps/index.html +++ b/Frontend Development/api/widget/interfaces/WidgetRendererProps/index.html @@ -4414,7 +4414,7 @@

    widgetInstanceId - January 24, 2024 + January 26, 2024 @@ -4424,7 +4424,7 @@

    widgetInstanceId - January 24, 2024 + January 26, 2024 diff --git a/Frontend Development/api/widget/variables/widgetConfigContext/index.html b/Frontend Development/api/widget/variables/widgetConfigContext/index.html index 68f28372..d84ff129 100644 --- a/Frontend Development/api/widget/variables/widgetConfigContext/index.html +++ b/Frontend Development/api/widget/variables/widgetConfigContext/index.html @@ -4323,7 +4323,7 @@

    widgetConfigContext

    - January 24, 2024 + January 26, 2024 @@ -4333,7 +4333,7 @@

    widgetConfigContext

    - January 24, 2024 + January 26, 2024 diff --git a/search/search_index.json b/search/search_index.json index 5313b1b3..09f6c1eb 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Telestion Developer Documentation","text":"

    Telestion is a framework for building telemetry applications. You can find more information about the project on the project website.

    This documentation is about developing a Ground Station software using Telestion. For end-user documentation, please ask your Telestion developer.

    Get started

    "},{"location":"#quick-links","title":"Quick links","text":""},{"location":"#github-repositories","title":"GitHub repositories","text":"
    • Telestion \u2013 The main repository for the Telestion project
    • Telestion Architecture \u2013 The repository that hosts the ADRs (Architecture Decision Records) for the Telestion project
    "},{"location":"#related-projects","title":"Related projects","text":"
    • NATS \u2013 The message bus used by Telestion
    • TypeScript \u2013 The programming language used for most components by Telestion
    • Deno \u2013 The runtime used by Telestion for TypeScript and JavaScript based services
    • React \u2013 The frontend framework used by Telestion
    "},{"location":"#discord","title":"Discord","text":"

    The Telestion Discord server is the best place to interact with the Telestion community. You can ask questions, get help, and discuss the project with other users and developers.

    Join the Discord server

    "},{"location":"getting-started/","title":"Getting started","text":"

    (coming soon)

    "},{"location":"message-bus/","title":"Message Bus","text":"

    The message bus is a simple, lightweight, and fast way to send messages between different parts (services) of your application. It\u2019s a publish/subscribe system that allows you to send messages to a specific subject and have any listeners on that subject receive the message.

    "},{"location":"message-bus/#messages","title":"Messages","text":"

    Messages are the way that data is sent between services. In the Telestion ecosystem. Messages are either JSON or binary data.

    "},{"location":"message-bus/#subjects","title":"Subjects","text":"

    Subjects are the way that messages are sent between services. Each subject has a name. The name is used to identify the subject.

    "},{"location":"message-bus/#publish-subscribe","title":"Publish / Subscribe","text":"

    The message bus is a publish/subscribe system. This means that you can publish messages to a specific subject and have any listeners on that subject receive the message.

    Warning

    Messages aren\u2019t stored when using the publish/subscribe method. This means that if a service isn\u2019t listening on a subject when a message gets published, it won\u2019t receive the message.

    If you need to ensure that a message is received, you can use the Request / Reply system to await confirmation.

    "},{"location":"message-bus/#example","title":"Example","text":"

    Here is an example of how the publish/subscribe system works:

    sequenceDiagram\n    accTitle: Sequence diagram of the publish/subscribe system. Text description in collapsed section below.\n    participant Service A\n    participant Message Bus\n    participant Service B\n    Service A->>Message Bus: Subscribe to subject \"test\"\n    Service B->>Message Bus: Publish message \"Hello World\" to subject \"test\"\n    Message Bus->>Service A: Message \"Hello World\" on subject \"test\"
    Text Description
    1. Service A subscribes to the subject \u201ctest\u201d on the message bus
    2. Service B publishes the message \u201cHello World\u201d to the subject \u201ctest\u201d
    3. The message bus sends the message \u201cHello World\u201d to Service A
    "},{"location":"message-bus/#request-reply","title":"Request / Reply","text":"

    The message bus is also a request/reply system. This means that you can send a request to a specific subject and have any listeners on that subject reply to the request.

    "},{"location":"message-bus/#example_1","title":"Example","text":"

    Here is an example of how the request/reply system works:

    sequenceDiagram\n    accTitle: Sequence diagram of the request/reply system. Text description in collapsed section below.\n    participant Service A\n    participant Message Bus\n    participant Service B\n    Service B->>Message Bus: Subscribe to subject \"test\"\n    Service A->>Message Bus: Send request \"Hello World\" to subject \"test\"\n    Message Bus->>Service B: Request \"Hello World\" on subject \"test\"\n    Service B->>Message Bus: Reply \"Hello World\" to subject \"test\"\n    Message Bus->>Service A: Reply \"Hello World\" on subject \"test\"
    Text Description
    1. Service B subscribes to the subject \u201ctest\u201d on the message bus
    2. Service A sends the request \u201cHello World\u201d to the subject \u201ctest\u201d
    3. The message bus sends the request \u201cHello World\u201d to Service B
    4. Service B replies to the request with \u201cHello World\u201d
    5. The message bus sends the reply \u201cHello World\u201d to Service A
    "},{"location":"message-bus/#nats","title":"NATS","text":"

    We use NATS as our message bus. While all other services can be replaced, the message bus is a core component of Telestion. It is the backbone of the entire system.

    "},{"location":"message-bus/#authentication-and-authorization","title":"Authentication and Authorization","text":"

    NATS also handles everything related to authentication and authorization for the message bus. You can easily control who can send and receive messages on which subjects.

    "},{"location":"project-folder-structure/","title":"Project folder structure","text":"

    Every Telestion project is different, and so is its folder structure. Some projects might not even have a frontend and write every backend service in Java, while others might have a frontend and use Deno for their backend services.

    That\u2019s not very helpful, is it? So, let\u2019s take a look at a folder structure that is suitable for most projects. Note that as your project grows, you might want to change the structure to better suit your needs. But you will know when the time has come.

    "},{"location":"project-folder-structure/#version-control","title":"Version control","text":"

    The first thing you should do is to create a new Git repository. This repository will contain all the code for your project. You can use GitHub, GitLab, or any other Git hosting service you like.

    "},{"location":"project-folder-structure/#recommended-folder-structure","title":"Recommended folder structure","text":"

    The following folder structure is recommended for most projects:

    • backend-deno - A folder that contains all backend services written in Deno.
      • [service-name] - A folder that contains a backend service written in Deno.
        • mod.ts - The entry point of the backend service.
        • README.md - A file that contains information about the backend service.
      • Dockerfile - A Dockerfile for the Deno-based backend services, if you want to use Docker.
    • frontend-react - A folder that contains the frontend written in React.
      • package.json - The frontend application\u2019s package.json file.
      • \u2026
    • frontend-cli - A folder that contains the CLI frontend written in Deno.
      • mod.ts - The entry point of the CLI.
      • README.md - A file that contains information about the CLI.
    • nats - A folder that contains the NATS server configuration.
      • nats-server.conf - The configuration file for the NATS server.
    • docker-compose.yml - A Docker Compose file that contains the configuration for the Docker containers.
    • README.md - A file that contains information about the project.
    "},{"location":"project-folder-structure/#alternatives","title":"Alternatives","text":"

    There are also other options how you could structure your project. For example, if you have completely distinct groups of services that are not related to each other, you could create a folder for each group, and differentiate between programming languages used under these groups.

    However, to get started, the above structure should be sufficient. You can always change it later.

    "},{"location":"service/","title":"Services","text":"

    Services are small, self-contained, and (ideally) stateless applications that can be deployed and scaled independently. They\u2019re designed to be used in conjunction with other services and are often packaged together to form a larger application.

    In less abstract terms, a service is a single application that is part of the bigger Telestion application. It is a single application that is responsible for a single task. For example, the project template contains the following services by default:

    • Frontend: A web application that is responsible for displaying the user interface
    • Database Service: A service that is responsible for storing data
    • Database Query Service: A service that is responsible for querying the database
    • Data Splitter Service: A service that is responsible for creating mock data to test the application
    "},{"location":"service/#service-types","title":"Service Types","text":"

    There are two types of services:

    • Frontend Services: Services that are responsible for displaying the user interface
    • Backend Services: Services that are responsible for processing data

    Info

    Concretely, the main difference between frontend and backend is that frontend services act on behalf of the user, while backend services act on behalf of the system.

    "},{"location":"service/#service-architecture","title":"Service Architecture","text":"

    While similar to the common microservice architecture, Telestion is less strict about its services. For example, Telestion services are not required to be stateless. While state in services makes it harder to scale them, it also makes it easier to develop them.

    Telestion services are also not required to be deployed independently. They can be deployed together as a single application.

    "},{"location":"service/#service-communication","title":"Service Communication","text":"

    Telestion services communicate via the NATS message bus. This means that they can send messages to each other and receive messages from each other. This allows them to communicate with each other without having to know each other\u2019s IP addresses or ports.

    "},{"location":"Backend%20Development/","title":"Developing Backend Services","text":"

    Backend services are small, self-contained, and (ideally) stateless applications that can be deployed and scaled independently. They are designed to be used in conjunction with other services and are often packaged together to form a larger application.

    ","tags":["Backend"]},{"location":"Backend%20Development/#example-structure","title":"Example Structure","text":"

    The following is an example for the combination of services creating the backend of a Telestion application:

    graph TB\n    accTitle: Diagram showcasing the structure of an exemplary Telestion backend. Text description in collapsible section below.\n    db[Database]\n    md[Mission Device]\n    subgraph Backend\n        io[IO Service]\n        tmps[Telemetry Parser Service]\n        tcs[Telecommand Service]\n        dbs[Database Writer Service]\n        dbqs[Database Query Service]\n    end\n    subgraph Frontend\n        wc[Web Client]\n    end\n    md <---> io\n    io --> tmps\n    tmps --> dbs\n    dbs --> db\n    wc --> dbqs\n    dbqs --> db\n    wc --> tcs\n    tcs --> io
    Text Description
    1. The Mission Device sends telemetry data to the IO Service.
    2. The IO Service (backend) forwards the telemetry data to the Telemetry Parser Service.
    3. The Telemetry Parser Service (backend) parses the telemetry data and writes it to the database via the Database Writer Service.
    4. The Database Writer Service (backend) writes the telemetry data to the database.
    5. The Web Client (frontend) queries the database via the Database Query Service.
    6. The Database Query Service (backend) queries the database and returns the data to the Web Client.
    7. The Web Client (frontend) sends telecommands to the Telecommand Service.
    8. The Telecommand Service forwards the telecommands to the IO Service.
    9. The IO Service sends the telecommands to the Mission Device.
    ","tags":["Backend"]},{"location":"Backend%20Development/#getting-started","title":"Getting Started","text":"

    The most common way to write a backend service is to use TypeScript.

    Get started writing a backend service in TypeScript

    However, for some use cases, it may be necessary to write a backend service in other languages.

    You can even write a backend service in any language you want. The only requirement is that it can communicate with the NATS message bus. To learn how to write a service in other languages, see Using other languages.

    ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/","title":"Using other languages","text":"

    You can use any language you want to write your backend. The only requirement is that it can communicate with the NATS message bus.

    ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#implementation-requirements","title":"Implementation Requirements","text":"

    The only technical requirement for a backend service is that it can communicate with the NATS message bus. This means that it must be able to send and receive messages on the message bus.

    However, there are some additional standards that you should follow to make your service easier to use (and compliant with the Telestion ecosystem):

    ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#deployment","title":"Deployment","text":"

    Your service should be deployable as both a Docker container and as an executable. This makes it easier to deploy and scale your service.

    ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#configuration","title":"Configuration","text":"

    Your service should be configurable via environment variables.

    Every Telestion service receives at least the following environment variables:

    • NATS_URL: The URL of the NATS server
    • NATS_USER: The username of the NATS user
    • NATS_PASSWORD: The password of the NATS user
    • SERVICE_NAME: The name of the service. This is used to create a unique queue group for your service. See Queues for more information.
    • DATA_DIR: The path to the data directory. This is where your service should store any data it needs to persist. This is shared between multiple services. To ensure that your service doesn\u2019t overwrite data from other services, you should create a subdirectory for your service.

    If your service doesn\u2019t receive any of these environment variables, it should exit with a non-zero exit code.

    Warning

    There can be multiple instances of a service with the same name running at the same time. They are guaranteed to have the same configuration. If you need a truly unique identifier, you can combine the SERVICE_NAME and the process ID.

    ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#logging","title":"Logging","text":"

    Your service should log any \u201cfeedback\u201d to stdout and stderr.

    ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#queues","title":"Queues","text":"

    NATS allows you to create queue groups. This means that you can have multiple instances of the same service running, and they\u2019ll share the messages they receive.

    If you want to use this feature, you should use the SERVICE_NAME environment variable to create a unique queue group for your service.

    ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#message-body","title":"Message Body","text":"

    Your message must be able to handle, without crashing, the following types of messages:

    • JSON-encoded UTF-8 strings
    • Binary data

    Your service mustn\u2019t assume anything about the format or content of the message body. It must be able to handle any message body of the two types.

    ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#health-checks","title":"Health Checks","text":"

    Your service should provide a health check feature on the message bus subject __telestion__/health. This allows other services to check if your service is still running.

    While running, any Telestion service should respond (within 0.5 seconds) to requests on the __telestion__/health subject with a message containing the following JSON-encoded information:

    {\n    \"errors\": 0, // or number of \"recent\" errors\n    \"name\": \"My Service\" // the SERVICE_NAME\n}\n
    ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#service-behavior-specification","title":"Service Behavior Specification","text":"

    A formal description of the behavior of a Telestion service is provided in the Service Behavior Specification. It can be used to test libraries for writing Telestion services in other languages.

    ","tags":["Backend"]},{"location":"Backend%20Development/rust/","title":"Writing a Backend Service in Rust","text":"","tags":["Backend","Rust"]},{"location":"Backend%20Development/rust/#prerequisites","title":"Prerequisites","text":"
    • Rust
    • Cargo
    • NATS server
    • NATS client
    • Tokio
    ","tags":["Backend","Rust"]},{"location":"Backend%20Development/rust/#connecting-to-the-message-bus","title":"Connecting to the Message Bus","text":"
    use nats::asynk::Connection;\nuse std::error::Error;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn Error>> {\n    let nc = Connection::new(\"nats://localhost:4222\").await?;\n    let sub = nc.subscribe(\"bar\")?.with_handler(move |msg| {\n        println!(\"Received {}\", &msg);\n        Ok(())\n    });\n\n    Ok(())\n}\n
    ","tags":["Backend","Rust"]},{"location":"Backend%20Development/rust/#getting-configuration-from-the-environment","title":"Getting configuration from the environment","text":"
    [dependencies]\ndotenv = \"0.15.0\"\n
    use dotenv::dotenv;\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn Error>> {\n    dotenv().ok();\n\n    let nats_url = env::var(\"NATS_URL\")?;\n    let nc = Connection::new(nats_url).await?;\n\n    Ok(())\n}\n
    ","tags":["Backend","Rust"]},{"location":"Backend%20Development/service-behavior/","title":"Service Behavior Specification","text":"

    Telestion services can be written in any language that supports the NATS protocol.

    While there can be differences in the implementation, there are some things that all Telestion services should have in common. This includes, among other things, the configuration of services, allowing seamless deployment of services written in different languages.

    "},{"location":"Backend%20Development/service-behavior/#gherkin","title":"Gherkin","text":"

    To specify these common behaviors, we use Gherkin. Gherkin is a language that is used to specify the behavior of software in a human-readable way while still being executable, meaning that tests can be automated.

    They are based on examples and should be written in a way that is independent of the implementation language.

    The Gherkin files are located in the backend-features directory of the Telestion project.

    "},{"location":"Backend%20Development/service-behavior/#documentation","title":"Documentation","text":"

    The Gherkin files get converted to Markdown files that are then included in the documentation.

    "},{"location":"Backend%20Development/service-behavior/auth/","title":"NATS authentication","text":""},{"location":"Backend%20Development/service-behavior/auth/#starting-the-service-with-valid-credentials","title":"Starting the service with valid credentials","text":"

    Given I have the basic service configuration

    And I have a NATS server running on \u201clocalhost:4222\u201d

    And the NATS server requires authentication

    And \u201cnats\u201d is a NATS user with password \u201cpassword\u201d

    And I have an environment variable named \u201cNATS_URL\u201d with value \u201clocalhost:4222\u201d

    And I have an environment variable named \u201cNATS_USER\u201d with value \u201cnats\u201d

    And I have an environment variable named \u201cNATS_PASSWORD\u201d with value \u201cpassword\u201d

    When I start the service

    Then the service should start

    And the service should connect to NATS.

    "},{"location":"Backend%20Development/service-behavior/auth/#starting-the-service-with-invalid-credentials-fails","title":"Starting the service with invalid credentials fails","text":"

    Given I have the basic service configuration

    And I have a NATS server running on \u201clocalhost:4222\u201d

    And the NATS server requires authentication

    And \u201cnats\u201d is a NATS user with password \u201cpassword\u201d

    And I have an environment variable named \u201cNATS_URL\u201d with value \u201clocalhost:4222\u201d

    And I have an environment variable named \u201cNATS_USER\u201d with value \u201cnats\u201d

    And I have an environment variable named \u201cNATS_PASSWORD\u201d with value \u201cwrong\u201d

    Then the service should fail to start.

    "},{"location":"Backend%20Development/service-behavior/auth/#starting-the-service-without-credentials-fails-when-the-authentication-is-required","title":"Starting the service without credentials fails when the authentication is required","text":"

    Given I have the basic service configuration

    And I have a NATS server running on \u201clocalhost:4222\u201d

    And the NATS server requires authentication

    And \u201cnats\u201d is a NATS user with password \u201cpassword\u201d

    And I have an environment variable named \u201cNATS_URL\u201d with value \u201clocalhost:4222\u201d

    Then the service should fail to start.

    "},{"location":"Backend%20Development/service-behavior/auth/#starting-the-service-fails-when-the-nats-server-is-offline","title":"Starting the service fails when the NATS server is offline","text":"

    Given I have the basic service configuration

    And I have a NATS server running on \u201clocalhost:4222\u201d

    And the NATS server requires authentication

    And \u201cnats\u201d is a NATS user with password \u201cpassword\u201d

    And I have an environment variable named \u201cNATS_URL\u201d with value \u201clocalhost:4222\u201d

    And I have an environment variable named \u201cNATS_USER\u201d with value \u201cnats\u201d

    And I have an environment variable named \u201cNATS_PASSWORD\u201d with value \u201cpassword\u201d

    And the NATS server is offline

    Then the service should fail to start.

    "},{"location":"Backend%20Development/service-behavior/config/","title":"Service Configuration","text":""},{"location":"Backend%20Development/service-behavior/config/#services-can-be-configured-through-environment-variables","title":"Services can be configured through environment variables","text":"

    The most common way to configure services is through environment variables. Environment variables are easy to use and can be set in a variety of ways. They are also easy to overwrite when running services locally.

    Given I have the basic service configuration

    And I have an environment variable named \u201cTEST\u201d with value \u201c1\u201d

    When I start the service without NATS

    Then the service should be configured with \u201cTEST\u201d set to \u201c1\u201d.

    "},{"location":"Backend%20Development/service-behavior/config/#services-can-be-configured-through-cli-arguments","title":"Services can be configured through CLI arguments","text":"

    Sometimes it is useful to configure services through CLI arguments. CLI arguments are easy to use and can be set when running services locally.

    Given I have the basic service configuration

    When I start the service with \u201c\u2013TEST=1\u201d without NATS

    Then the service should be configured with \u201cTEST\u201d set to \u201c1\u201d.

    "},{"location":"Backend%20Development/service-behavior/config/#trying-to-run-services-without-providing-the-required-configuration-fails","title":"Trying to run services without providing the required configuration fails","text":"

    There are some configuration values that are required for services to run. If these values are not provided, the service should fail to start. - NATS_URL - to connect to NATS - SERVICE_NAME - to group services in NATS when subscribing with multiple instances - DATA_DIR - a directory where the service is free to store persistent data

    During development, it is possible to use the development mode so you don\u2019t have to provide these values. However, this is not recommended for production.

    Given I have no service configuration

    Then the service should fail to start.

    "},{"location":"Backend%20Development/service-behavior/config/#cli-arguments-overwrite-environment-variables","title":"CLI arguments overwrite environment variables","text":"

    To make it easy to overwrite configuration values when running services locally, CLI arguments should overwrite environment variables.

    Given I have the basic service configuration

    And I have an environment variable named \u201cTEST\u201d with value \u201c1\u201d

    When I start the service with \u201c\u2013TEST=2\u201d without NATS

    Then the service should be configured with \u201cTEST\u201d set to \u201c2\u201d.

    "},{"location":"Backend%20Development/service-behavior/dev-mode/","title":"Development mode","text":""},{"location":"Backend%20Development/service-behavior/dev-mode/#the-service-can-be-started-in-dev-mode-to-use-default-parameters-during-development","title":"The service can be started in dev mode to use default parameters during development","text":"

    During development, it is useful to start the service with default parameters, so that it can be used without any configuration.

    Given I have no service configuration

    And I have a NATS server running on \u201clocalhost:4222\u201d

    When I start the service with \u201c\u2013dev\u201d without NATS

    Then the service should start

    And the service should be configured with \u201cNATS_USER\u201d set to \u201cundefined\u201d

    And the service should be configured with \u201cNATS_PASSWORD\u201d set to \u201cundefined\u201d.

    "},{"location":"Backend%20Development/service-behavior/dev-mode/#any-custom-configuration-overwrites-dev-mode-parameters","title":"Any custom configuration overwrites dev mode parameters","text":"

    Given I have no service configuration

    And I have a NATS server running on \u201clocalhost:4255\u201d

    And I have an environment variable named \u201cNATS_URL\u201d with value \u201clocalhost:4255\u201d

    When I start the service with \u201c\u2013dev \u2013DATA_DIR=/tmp\u201d

    Then the service should start

    And the service should connect to NATS

    And the service should be configured with \u201cDATA_DIR\u201d set to \u201c/tmp\u201d

    And the service should be configured with \u201cNATS_URL\u201d set to \u201clocalhost:4255\u201d.

    "},{"location":"Backend%20Development/service-behavior/nats/","title":"NATS Integration in Services","text":""},{"location":"Backend%20Development/service-behavior/nats/#the-service-has-access-to-the-nats-client-after-startup","title":"The service has access to the NATS client after startup","text":"

    The service should be able to access the NATS client after startup. This enables service developers to use the NATS client to publish and subscribe to messages.

    Given I have the basic service configuration

    And I have a NATS server running on \u201clocalhost:4222\u201d

    When I start the service

    Then the service should connect to NATS

    And the NATS connection API should be available to the service.

    "},{"location":"Backend%20Development/service-behavior/nats/#the-developer-disables-the-nats-integration","title":"The developer disables the NATS integration","text":"

    The developer may want to disable the NATS integration for testing purposes or because the service does not need NATS.

    Given I have the basic service configuration

    And I have a NATS server running on \u201clocalhost:4222\u201d

    When I start the service without NATS

    Then the service should not connect to NATS.

    "},{"location":"Backend%20Development/service-behavior/service/","title":"Service Lifecycle","text":""},{"location":"Backend%20Development/service-behavior/service/#starting-a-service","title":"Starting a service","text":"

    The most trivial scenario of them all. We start the service and it should start. That\u2019s it. No more, no less. But it\u2019s a good start.

    Given I have the basic service configuration

    And I have a NATS server running on \u201clocalhost:4222\u201d

    When I start the service

    Then the service should start.

    "},{"location":"Backend%20Development/typescript/","title":"Writing a Backend Service in TypeScript","text":"

    TypeScript is the recommended language for writing backend services. It is a superset of JavaScript that adds static typing and other features that make it easier to write and maintain code.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#prerequisites","title":"Prerequisites","text":"

    To write a backend service in TypeScript, you should be familiar with JavaScript and (ideally) TypeScript. Overall, basic JavaScript knowledge will be sufficient to get started, but async/await and Promises are used extensively for services, so you should be familiar with these topics.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#deno","title":"Deno","text":"

    Deno is a JavaScript/TypeScript runtime that is built on top of V8, Rust, and Tokio. It is a secure runtime for JavaScript and TypeScript.

    Compared to Node.js, Deno has the following advantages:

    • It has built-in TypeScript support
    • It has built-in security features
    • It\u2019s easier to deploy
    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#installing-deno","title":"Installing Deno","text":"

    To install Deno, please follow the instructions on the Deno website .

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#writing-a-basic-service","title":"Writing a basic Service","text":"","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#creating-a-new-service","title":"Creating a new Service","text":"

    Create a new directory for your service:

    mkdir my-service\ncd my-service\n

    Create a new file called service.ts:

    touch service.ts\n
    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#writing-the-service","title":"Writing the Service","text":"

    Open service.ts in your favorite editor and add the following code:

    service.ts
    import { startService } from 'https://deno.land/x/telestion/mod.ts';// (1)!\n\nawait startService/*(2)!*/({\n    nats: false,// (3)!\n});\n\nconsole.log('Hello World!');// (4)!\n
    1. Import the startService function from the library.
    2. Start the service. This automatically connects to NATS and does some other setup.
    3. Disable NATS. We don\u2019t need it for this example and it would otherwise throw an error because we haven\u2019t configured it yet.
    4. Log a message to the console when the service starts.
    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#running-the-service","title":"Running the Service","text":"

    To run the service, run the following command:

    deno run --allow-all service.ts --dev\n

    Success

    You should see the following output:

    Running in development mode. Using default values for missing environment variables.\nHello World!\n

    Running in development mode

    When you run the service with the --dev flag, the service will use default values for missing environment variables. You\u2019ll learn more about this in the configuration section.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#next-steps","title":"Next Steps","text":"

    Now that you have a basic service running, you should have a look at how to make your service configurable.

    Read more about configuration

    If you prefer to learn by example, you can also have a look at the samples.

    Browse samples on GitHub

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/","title":"Service Configuration","text":"

    Tip

    Not every service needs to be configurable. If you are writing a simple service, you can skip this section.

    However, you can often save yourself a lot of time by making your service configurable. This way, you can use the same service in multiple environments without having to change the code.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#configuration-sources","title":"Configuration Sources","text":"

    Services can be configured using the following sources:

    • Environment variables
    • Command line arguments
    • An optional configuration file (JSON)

    All these sources get combined into a single configuration object. If a configuration value is defined in multiple sources, the following order is used:

    1. Command line arguments
    2. Environment variables
    3. Configuration file
    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#environment-variables","title":"Environment Variables","text":"

    Environment variables are the most common way to configure a service. They are easy to use and supported by most platforms.

    Environment variables are always strings. If you need to use a different type, you will have to parse the value yourself.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#command-line-arguments","title":"Command Line Arguments","text":"

    Command line arguments are useful for configuring a service during development. They are also useful for overriding configuration values when running a service in production.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#configuration-file","title":"Configuration File","text":"

    Configuration files are useful for configuring a service in production. They are also useful for overriding configuration values when running a service in production.

    Configuration files are optional. If no configuration file is provided, the service will still start.

    A configuration file is a JSON file with an object as its root element. The keys of this object are the configuration values. The values of this object are the configuration values.

    The configuration file is loaded from the path passed as CONFIG_FILE as either environment variable or command line argument.

    You can optionally also pass a CONFIG_KEY to load a specific key from the configuration file. This is useful if you want to use the same configuration file for multiple services.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#configuration-precedence-overview-diagram","title":"Configuration Precedence Overview Diagram","text":"
    graph TB\n    accTitle: Diagram of the configuration sources and their order of precedence. Text description in collapsed section below.\n    A[Environment Variables] --merged into--> C[Preliminary Configuration]\n    B[Command line arguments] --merged into with priority--> C\n    C -.CONFIG_FILE.-> D[Configuration File]\n    D --merged into--> E[Configuration Object]\n    C --merged into with priority--> E

    Configuration sources and their order of precedence.

    Text Description
    1. Environment variables are merged into the preliminary configuration.
    2. Command line arguments are merged into the preliminary configuration with priority.
    3. The configuration file is loaded (based on the CONFIG_FILE parameter of the preliminary configuration) and merged into the preliminary configuration.
    4. The preliminary configuration is merged into the configuration object with priority.
    5. The configuration object gets returned.
    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#minimal-configuration-values","title":"Minimal Configuration Values","text":"

    Some configuration values are required for all services. These values are:

    • NATS_URL: The URL of the NATS server to connect to.
    • NATS_USER (if the NATS server requires authentication): The username to use when connecting to NATS.
    • NATS_PASSWORD (if the NATS user requires authentication): The password to use when connecting to NATS.
    • SERVICE_NAME: The name of the service. This is used to identify the service in the logs and in the NATS server. This is required for all services.
    • DATA_DIR: The directory where the service can store data. This is required for all services.

    Tip

    To make it easier to run your service during development, sensible defaults are used when you pass the --dev flag to the service:

    Configuration Value Default Value NATS_URL localhost:4222 NATS_USER (none) NATS_PASSWORD (none) SERVICE_NAME dev-[process gid] DATA_DIR ./data

    This way, you don\u2019t have to set all the required configuration values when running the service locally.

    Without the --dev flag, the service fails if any of the required configuration values are missing.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#accessing-the-configuration","title":"Accessing the Configuration","text":"

    Now that you know about the different configuration sources, let\u2019s see how you can access the configuration in your service. Since the complicated bits are handled by the startService function, this is actually pretty straight forward.

    Create a file called config.json next to your service.ts file with the following content:

    config.json
    {\n  \"SERVICE_NAME\": \"Config Tester\",\n  \"tasks\": {\n    \"task1\": \"Task 1\",\n    \"task2\": \"Task 2\"\n  }\n}\n

    Now, let\u2019s adjust the service.ts file to use the configuration:

    service.ts
    import { startService } from \"https://deno.land/x/telestion/mod.ts\";\nimport { z } from \"https://deno.land/x/zod@v3.21.4/mod.ts\";// (1)!\n\nconst { config: rawConfig/* (2)! */} = await startService({\n  nats: false,\n});\n\nconst config = z.object({\n  NAME: z.string(),\n  tasks: z.record(z.string(), z.string()),\n}).parse(rawConfig);// (3)!\n\nconsole.log(config.NAME, config.tasks);// (4)!\n
    1. Import the z function from the Zod to validate the configuration. Never assume the configuration is valid. Always validate it before using it.
    2. Save the raw configuration in a variable called rawConfig.
    3. Validate the configuration using Zod. This will throw an error if the configuration is invalid.
    4. You can now safely use the configuration in your service. If the configuration is invalid, the service will not start.

    Now, let\u2019s see what happens if we run the service:

    deno run --allow-all service.ts --dev\n

    As expected, the service doesn\u2019t start:

    $ deno run --allow-all service.ts --dev\nRunning in development mode.\nUsing default values for missing environment variables.\nerror: Uncaught ZodError: [\n  {\n    \"code\": \"invalid_type\",\n    \"expected\": \"string\",\n    \"received\": \"undefined\",\n    \"path\": [\n      \"NAME\"\n    ],\n    \"message\": \"Required\"\n  },\n  {\n    \"code\": \"invalid_type\",\n    \"expected\": \"object\",\n    \"received\": \"undefined\",\n    \"path\": [\n      \"tasks\"\n    ],\n    \"message\": \"Required\"\n  }\n]\n

    Let\u2019s fix this by passing the required configuration values:

    deno run --allow-all service.ts --dev \\\n  --CONFIG_FILE ./config.json \\ # (1)!\n  --NAME \"Hello\" # (2)!\n
    1. Pass the path to the configuration file using the --CONFIG_FILE flag.
    2. Pass the NAME configuration value using the --NAME flag.

    Now, everything works as expected.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/e2e-log-service/","title":"End to end example: Log Service","text":"

    Note

    The author generated this text in part with GPT-3, OpenAI\u2019s large-scale language-generation model. Upon generating draft language, the author reviewed, edited, and revised the language to their own liking and takes ultimate responsibility for the content of this publication.

    This tutorial will explain step-by-step how to write a log service that will listen for messages on the log.> subject and write them to a file.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/e2e-log-service/#steps","title":"Steps","text":"
    1. First, we need to import the startService function from our library (lib.ts) and the encode function from the standard Deno library.

      import { startService } from \"https://deno.land/x/telestion/mod.ts\";\nimport { encode } from \"https://deno.land/std@0.186.0/encoding/hex.ts\";\n
    2. Next, we create a new TextEncoder instance. This will be used to turn messages into a format that can be written to a file.

      const encoder = new TextEncoder();\n
    3. We then call the startService function to set up our service. This will return an object containing information about the message bus that we can use to subscribe to messages.

      const { messageBus } = await startService();\n
    4. We then subscribe to the message bus, using a wildcard subscription for any messages published on the log.> subject. This will allow us to receive all messages published on any topics starting with log..

      const logMessages = messageBus.subscribe(\"log.>\");\n
    5. We use a for-await-of loop to receive messages from the message bus. For each message, we extract the subject (split the string on ., then take the second element) and the message data, which we encode using the encode function from the standard library.

      for await (const msg of logMessages) {\n  try {\n    const currentTime = new Date().toISOString();\n    const logMessage = encode(msg.data).toString();\n    const subject = msg.subject.split(\".\")[1];\n
    6. We log the message to the console and write it to a file (appending it to the end).

          console.log(`${currentTime} [${subject}] ${logMessage}`);\n    await Deno.writeFile(\n      \"log.txt\",\n      encoder.encode(`${currentTime} [${subject}] ${logMessage}\\n`),\n      { append: true },\n    );\n  } catch (error) {\n    console.error(error);\n  }\n}\n

    And that\u2019s it! Our service is now complete and ready to be used.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/e2e-log-service/#final-code","title":"Final Code","text":"
    import { startService } from \"https://deno.land/x/telestion/mod.ts\";\nimport { encode } from \"https://deno.land/std@0.186.0/encoding/hex.ts\";\n\nconst encoder = new TextEncoder();\n\nconst { messageBus } = await startService();\n\nconst logMessages = messageBus.subscribe(\"log.>\");\n\nfor await (const msg of logMessages) {\n  try {\n    const currentTime = new Date().toISOString();\n    const logMessage = encode(msg.data).toString();\n    const subject = msg.subject.split(\".\")[1];\n\n    console.log(`${currentTime} [${subject}] ${logMessage}`);\n    await Deno.writeFile(\n      \"log.txt\",\n      encoder.encode(`${currentTime} [${subject}] ${logMessage}\\n`),\n      { append: true },\n    );\n  } catch (error) {\n    console.error(error);\n  }\n}\n
    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/","title":"Interacting with the Message Bus","text":"

    The message bus is a simple, lightweight, and fast way to send messages between different parts (services) of your application. It is a simple publish/subscribe system that allows you to send messages to a specific subject and have any listeners on that subject receive the message.

    Running NATS for development

    Now that we want to interact with the message bus, we need to have NATS running. If you\u2019re using the --dev mode for testing your service, it\u2019s sufficient to run the nats-server executable in a separate terminal window. This will start a local NATS server on port 4222 which is the default port for NATS.

    If you have a prdouction-like setup, you\u2019ll need to pass the NATS_USER and NATS_PASSWORD corresponding to your NATS configuration as configuration parameters to your service for authentication.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#connecting-to-the-message-bus","title":"Connecting to the Message Bus","text":"

    Connecting to the event bus is automatically handled by the startService function. It will connect to the message bus using the NATS_URL environment variable. If you\u2019re running the service in --dev mode, this will be nats://localhost:4222 by default.

    All you need to do compared to the previous examples is to omit the { nats: false } parameter from the startService function call:

    service.ts
    import {\n    startService\n} from \"https://deno.land/x/telestion/mod.ts\";\n\nconst {nc/* (1)! */} = await startService(/* (2)! */);\n
    1. Store the NATS connection in a variable called nc for later use.
    2. Omit the { nats: false } parameter from the startService function call since we want to connect to the message bus.

    Note

    startService actually returns an object containing the NATS connection (nc) and a few other things. In our example, we use destructuring to only get the nc variable. This is equivalent to the following code:

    const service = await startService();\nconst nc = service.nc;\n
    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#publishing-messages","title":"Publishing Messages","text":"

    Publishing messages is as simple as calling the publish function on the NATS connection:

    await nc.publish(\"subject\"/*(1)!*/, message/*(2)!*/);\n
    1. The subject (sometimes also called channel) to which the message gets published.
    2. The message data (also called payload or body).

    However, Telestion Hub uses a specific message format for all messages sent over the message bus. A message can be either JSON or a binary message. The binary message is used for sending large amounts of data, e.g., images or video streams. The JSON message is used for all other messages.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#json-messages","title":"JSON Messages","text":"

    To send a JSON message, you need to create a JSON object and pass it to the publish function:

    service.ts
    import {\n    JSONCodec,\n    startService\n} from \"https://deno.land/x/telestion/mod.ts\";\n// or: import { JSONCodec } from \"https://deno.land/x/nats/src/mod.ts\";\n\nconst {nc} = await startService();\n\nconst jsonCodec = JSONCodec();//(2)!\n\nawait nc.publish(\"subject\", jsonCodec.encode/*(3)!*/({\n    foo: \"some arbitrary JSON-compatible data\",\n    bar: 42\n}));\n
    1. Import the JSONCodec (for convenience, this gets re-exported by the lib.ts, but you can also import it directly from the NATS library).
    2. Create a new JSONCodec instance.
    3. Encode the JSON object using the JSONCodec instance.
    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#binary-messages","title":"Binary Messages","text":"

    To send a binary message, you need to create a Uint8Array containing the bytes and pass it to the publish function:

    service.ts
    import {\n    startService\n} from \"https://deno.land/x/telestion/mod.ts\";\n\nconst {nc} = await startService();\n\nawait nc.publish(\"subject\", new Uint8Array([0x01, 0x02, 0x03]));\n

    Uint8Arrays

    You can learn more about how you can use Uint8Array on MDN.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#subscribing-to-messages","title":"Subscribing to Messages","text":"

    There are multiple ways to subscribe to messages on a subject. The most common way is to use the subscribe function in combination with a for await loop:

    service.ts
    import {\n    startService\n} from \"https://deno.land/x/telestion/mod.ts\";\n\nconst {nc} = await startService();\n\nconst subjectSubscription/*(1)!*/ = await nc.subscribe(\"subject\"/*(2)!*/);\n\nfor await (const message of subjectSubscription) {//(3)!\n    console.log(message.data);//(4)!\n}\n
    1. Store the subscription in a variable called subjectSubscription for later use.
    2. Subscribe to the subject subject.
    3. For each message received on the subject, \u2026
    4. \u2026 print the message data to the console.

    Unfortunately, this won\u2019t decode our JSON messages automatically. We need to do this ourselves:

    service.ts
    import {\n    JSONCodec,\n    startService\n} from \"https://deno.land/x/telestion/mod.ts\";\n\nconst {nc} = await startService();\n\nconst jsonCodec = JSONCodec();\n\nconst subjectSubscription = await nc.subscribe(\"subject\");\nfor await (const message of subjectSubscription) {\n    const jsonMessage = jsonCodec.decode(message.data);//(1)!\n    console.log(jsonMessage.foo);//(2)!\n}\n
    1. Decode the message data using the JSONCodec instance.
    2. Print the foo property of the decoded JSON message to the console.

    Danger

    Can you spot the problem with this code? What happens if the message data doesn\u2019t contain a foo property? Or if it\u2019s not a JSON message at all? This would lead to our service crashing!

    Never assume a message\u2019s structure!

    You should always validate the message data before using it. We\u2019ll cover this in the next section.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#validating-messages","title":"Validating Messages","text":"

    A Telestion service must validate all messages it receives. This is to ensure that the service doesn\u2019t crash when it receives invalid messages.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#validating-the-message-type","title":"Validating the message type","text":"

    The first \u201clayer\u201d of validation is the message type. A message can either be a JSON message or a binary message. The jsonCodec.decode function will throw an error if the message data is not a valid JSON message. Therefore, we can use a try/catch block to catch the error and handle it accordingly:

    service.ts
    // ...\n\nfor await (const message of subjectSubscription) {\n    try/*(3)!*/{\n        const jsonMessage = jsonCodec.decode(message.data);\n        console.log(jsonMessage.foo);\n    } catch (_e) {\n        console.error/*(2)!*/(\"Received invalid message:\", message);\n    }\n}\n
    1. Catch the error thrown by jsonCodec.decode.
    2. Print the error message to the console (or do whatever else you want to do when you receive an invalid message).
    3. Wrap the code that decodes the message in a try/catch block.

    Binary Messages

    Since any messages get sent as binary messages (in fact, the JSONCodec does nothing else than convert the JSON message to a Uint8Array and back), there\u2019s no way to validate that a message is supposed to be a binary message. This makes the next section even more important.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#validating-the-message-structure","title":"Validating the message structure","text":"

    The second \u201clayer\u201d of validation is the message structure. This is where you validate that the message data contains all the properties you expect it to contain. For example, if you expect a message to contain a foo property, you must verify its existence before using it.

    For structured JSON data, we recommend that you use the zod library for validation. This is also used in our lib.ts file to validate the configuration. You can find more information about zod in the library\u2019s GitHub repository.

    Let\u2019s create a zod schema for our JSON message in a new file called foo-message.ts:

    foo-message.ts
    import {\n    z\n} from \"https://deno.land/x/zod@v3.16.1/mod.ts\";\n\nexport const fooMessageSchema = z.object/*(1)!*/(({\n    foo: z.string()/*(2)!*/,\n    bar: z.number().min(-10)/*(3)!*/\n});\n\nexport type FooMessage = z.infer<typeof fooMessageSchema>;//(4)!\n
    1. A FooMessage must be an object.
    2. A FooMessage must have a foo property that is a string.
    3. A FooMessage must have a bar property that is a number and is greater than or equal to -10.
    4. This is a TypeScript type that represents the FooMessage type. While we won\u2019t use it in this example, it\u2019s good practice to create a type for each schema you create. This allows you to use the type anywhere in your code:
      function foo(message: FooMessage) {\n     console.log(message.foo);\n}\n\n// ...\n\nconst fooMessage = fooMessageSchema.parse(\n     jsonCodec.decode(message.data)\n);\nfoo(fooMessage); // This works now!\n

    Now we can use this schema to validate the message data:

    service.ts
    import {\n    fooMessageSchema\n} from \"./foo-message.ts\";\n\n// ...\n\nfor await (const message of subjectSubscription) {\n    try {\n        const jsonMessage = fooMessageSchema.parse/*(1)!*/(\n            jsonCodec.decode(message.data)\n        );\n\n        console.log(jsonMessage/*(2)!*/.foo);\n    } catch (_e) {\n        console.error(\"Received invalid message:\", message);\n    }\n}\n
    1. Validate the message data using the fooMessageSchema schema. This will throw an error if the message data doesn\u2019t match the schema.
    2. TypeScript now knows that jsonMessage is a valid FooMessage object. Therefore, we can access the foo property without any problems.

    Success

    If your editor has great TypeScript support and has shown you warnings/errors before, they are now gone! This is because TypeScript now knows that the jsonMessage variable is a valid FooMessage object. In other words, your code is now safe from invalid messages!

    Binary Messages

    For binary messages, you can\u2019t use zod to validate the message structure. Instead, you should use the Uint8Array methods to validate the message structure. For example, you can check the length of the message data using the length property of the Uint8Array:

    if (message.data.length !== 3) {\n    console.error(\"Received invalid message:\", message);\n}\n

    However, the exact validation required completely depends on your use case. Just make sure that your code doesn\u2019t crash when it receives an invalid message.

    ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#subscribing-to-multiple-topics","title":"Subscribing to Multiple Topics","text":"

    So far, we\u2019ve used the for await loop. This is a convenient way to subscribe to a single topic. However, if you want to do more than just react to messages from a specific subject, we get into trouble. Since the for await loop is blocking, we can\u2019t do anything else while we\u2019re waiting for messages.

    We can solve this by wrapping the for await loop in an async function and calling it in a separate thread. This allows us to do other things while we\u2019re waiting for messages:

    service.ts
    // ...\n\nconst subjectMessages = nc.subscribe(\"foo\");\n(async () => {//(1)!\n    for await (const message of subjectMessages) {\n        // Handle messages from the \"foo\" subject\n    }\n})();\n\n// ... (2)\n
    1. Wrap the for await loop in an async function and call it immediately. This will start the subscription in parallel to the rest of the code.
    2. Do other things while we\u2019re waiting for messages.

    Note that we\u2019re storing the return value of nc.subscribe in a variable outside the async function. This is important so that we can close the subscription or check its status later.

    Closing the Subscription

    You can close the subscription by calling the unsubscribe method on the subscription object:

    const subjectMessages = nc.subscribe(\"foo\");\n// ...\nsubjectMessages.unsubscribe();\n

    You must call unsubscribe on the subscription object. Calling nc.unsubscribe will unsubscribe from all subscriptions!

    This now allows us to subscribe to multiple topics:

    service.ts
    // ...\n\nconst fooMessages = nc.subscribe(\"foo\");//(1)!\n(async () => {\n    for await (const message of fooMessages) {\n        // Handle messages from the \"foo\" subject\n    }\n})();\n\nconst barMessages = nc.subscribe(\"bar\");//(2)!\n(async () => {\n    for await (const message of barMessages) {\n        // Handle messages from the \"bar\" subject\n        if (shouldUnsubscribeFoo(message))\n            fooMessages.unsubscribe/*(3)!*/();\n\n        if (shouldUnsubscribeBar(message))\n            barMessages.unsubscribe/*(4)!*/();\n    }\n})();\n\nawait Promise.all/*(5)!*/([\n    fooMessages.closed,\n    barMessages.closed\n]);\n\nconsole.log(\"All subscriptions closed!\");//(6)!\n
    1. Subscribe to the foo subject.
    2. Subscribe to the bar subject (in parallel to the foo subscription).
    3. Unsubscribe from the foo subject if the shouldUnsubscribeFoo function returns true.
    4. Unsubscribe from the bar subject if the shouldUnsubscribeBar function returns true.
    5. Wait for both subscriptions to close. This will happen when the unsubscribe method is called on the subscription object.

      The closed property is a Promise that resolves when the subscription is closed.

      Promise.all is a convenient way to wait for multiple promises to resolve. It returns a Promise that resolves when all promises passed to it have resolved.

    6. Log a message when both subscriptions are closed.
    7. ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#queue-groups","title":"Queue Groups","text":"

      Info

      Queue groups are a way to distribute messages between multiple subscribers. If you have multiple subscribers to a subject, you can use queue groups to distribute messages between them. This is useful if you want to distribute messages between multiple instances of a service (for example, if you want to scale your service horizontally because processing a message takes too long).

      All you have to do to use queue groups is to pass a queue option to the subscribe method. You can use any string as the queue name, but by its definition, the SERVICE_NAME configuration parameter works perfect for this. For convenience, this gets exposed as serviceName on the object returned by startService:

      service.ts
      // ...\n\nconst {\n    nc,\n    serviceName/*(1)!*/\n} = await startService();\n\nconst fooMessages = nc.subscribe(\n    \"foo\", \n    {queue: serviceName/*(2)!*/}\n);\n(async () => {\n    for await (const message of fooMessages) {\n        // Handle messages from the \"foo\" subject\n    }\n})();\n\n// ...\n
      1. Get the serviceName from the object returned by startService.
      2. Pass the serviceName as the queue option to the subscribe method.

      If you now run multiple instances of your service, you\u2019ll see that messages are distributed between them. This is because the queue option tells the message bus to distribute messages between all subscribers with the same queue name.

      Service names in development mode

      When you run your service in development mode, the serviceName will be generated. This means that you\u2019ll get a different service name every time you start your service. To avoid this, you can either set the SERVICE_NAME environment variable or pass a service name via the CLI:

      deno run --allow-all service.ts --dev --SERVICE_NAME=foo\n
      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#wildcards","title":"Wildcards","text":"

      Wildcards are a way to subscribe to multiple subjects at once. This is useful if you want to subscribe to multiple subjects that have a common prefix. For example, you could have a service that handles all requests to the /api endpoint. You could then subscribe to all requests to the /api endpoint by subscribing to the api.> subject.

      There are two types of wildcards: * and >. The * wildcard matches a single token. The > wildcard matches one or more tokens. For example, the api.* subject matches api.foo and api.bar, but not api.foo.bar. The api.> subject matches api.foo, api.bar, and api.foo.bar.

      You can use wildcards in the subscribe method and then use the subject property of the message to check which subject the message was sent to:

      service.ts
      // ...\n\n/**\n * A simple key-value store.\n */\nconst store: Record<string, unknown> = {};\n\nconst kvMessages = nc.subscribe/*(1)!*/(\"kv.>\");\n(async () => {\n    for await (const message of kvMessages) {\n        try {\n            const [_kv, action, ...keyParts] =\n                message.subject.split/*(2)!*/(\".\");\n\n            const key = keyParts.join(\".\");\n\n            if (action === \"get\") {\n                // retrieve the value from the store\n                message.respond(\n                    jsonCodec.encode(store[key])\n                );\n            } else if (action === \"set\") {\n                // set the value in the store\n                store[key] = jsonCodec.decode(message.data);\n                message.respond(jsonCodec.encode({ok: true});\n            }\n        } catch (error) {\n            message.respond(\n                jsonCodec.encode({error: error.message})\n            );\n        }\n    }\n})();\n
      1. Subscribe to the kv.> subject. This matches all subjects that start with kv..
      2. Split the subject into tokens. The first token is kv, the second token is the action, and the rest of the tokens are the key. We store these into variables using array destructuring.

      In this example, we subscribe to the foo.* subject. We then use the subject property of the message to check which action was requested. If the action is get, we get the value from the store object and respond with it. If the action is set, we set the value in the store object.

      For example, if we send a message to the foo.get.bar subject, we\u2019ll get the value of the bar key in the store object. If we send a message to the foo.set.bar subject with the value 42, we\u2019ll set the value of the bar key in the store object to 42.

      Success

      Woohoo! You\u2019ve just re-implemented a key-value store using the message bus, which (with a few convenience features on top) is an essential part of Telestion\u2019s standard services!

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#requestreply","title":"Request/Reply","text":"

      So far, we\u2019ve looked at publishing messages and subscribing to messages. However, there\u2019s one more thing we can do with the message bus: request/reply.

      Request/reply is a pattern where one service sends a request to another service and waits for a response. This is useful if you want to get data from another service. For example, you could have a service that stores data in a database. Other services can then request data from this service.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#sending-a-request","title":"Sending a Request","text":"

      Let\u2019s start by looking at how we can send a request. We can use the request method on the NatsConnection object to send a request. This makes it incredibly easy to send a request:

      service.ts
      // ...\n\nconst response = await nc.request/*(1)!*/(\n    \"fooRequest\"/*(2)!*/,\n    jsonCodec.encode({foo: \"bar\"})/*(3)!*/\n);\nconsole.log(response.data);\n
      1. Call the request method on the NatsConnection object. This method returns a Promise that resolves when the response is received. The response has the same form as the messages we\u2019ve already seen in our for await loops.
      2. Specify the subject to send the request to.
      3. Encode the request message data using the jsonCodec codec. This is the same as we\u2019ve done before.

      Tip: Specifying a timeout

      As it is, our code will wait forever for a response. This is probably not what we want. We can specify a timeout by passing a second argument to the request method:

      const response = await nc.request(\n    \"fooRequest\", \n    jsonCodec.encode({foo: \"bar\"}),\n    {timeout: 1000}\n);\n

      This will cause the request method to reject the Promise if no response is received within 1000 milliseconds. Make sure to handle the rejection by handling it appropriately.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#handling-a-request","title":"Handling a Request","text":"

      Now that we know how to send a request, let\u2019s look at how we can handle a request. We can use the subscribe method on the NatsConnection object to subscribe to a subject. This allows us to handle requests:

      service.ts
      // ...\n\nconst requestMessages = nc.subscribe/*(1)!*/(\"fooRequest\");\n\n(async () => {\n    for await (const message of requestMessages) {//(2)!\n        message.respond/*(3)!*/(jsonCodec.encode({bar: \"baz\"}));\n    }\n})();\n
      1. Subscribe to the fooRequest subject as usual.
      2. Iterate over the messages received from the fooRequest subject as usual.
      3. Respond to the request by calling the respond method on the message object. This method takes a single argument: the response message data. This is the same as we\u2019ve done before.

      Tip

      The message received from the fooRequest subject is the same as the message received from the foo subject. This means that we can use the same steps to handle the message as we\u2019ve done before if we need the data to handle the request.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#related-links","title":"Related Links","text":"

      While we\u2019ve covered the basics of interacting with the message bus in this article, there are a few more things you can do with the message bus. You can find more information about the message bus in the NATS documentation. While the connection to the message bus is handled by the startService function, topics like receiving and sending messages are covered more extensively (including useful concepts like request/reply, queue groups, etc.) in the NATS documentation.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/samples/","title":"Samples","text":"

      You can find even more samples in the project\u2019s GitHub repository under backend-deno/samples:

      Browse samples on GitHub

      "},{"location":"Backend%20Development/typescript/samples/#running-the-samples","title":"Running the samples","text":"

      You can run all the samples using the docker-compose.yml file in the linked folder. Just run the following command:

      docker-compose up\n

      This will run all the samples, including the required NATS server.

      "},{"location":"Deployment/","title":"Deployment","text":"

      Deployment is the process of making a software system available for use. In the context of Telestion, deployment refers to the process of making the Telestion application available for use.

      Warning

      The deployment process is heavily dependent on the specific use case. The following documentation is intended to give a general overview of the deployment process that\u2019s available by default in new Telestion Projects.

      Depending on your project, you may need to adapt the deployment process to your specific needs.

      ","tags":["Deployment"]},{"location":"Deployment/#deployment-methods","title":"Deployment Methods","text":"

      Telestion can be deployed in multiple ways:

      • Local Deployment
      • Docker Deployment
      • Kubernetes Deployment

      Info

      The local deployment is the easiest way to get started with Telestion. You should probably start with the local deployment and then move on to the other deployment methods as needed.

      ","tags":["Deployment"]},{"location":"Deployment/#nats-and-its-configuration","title":"NATS and its configuration","text":"

      Telestion uses NATS as its message broker. NATS is a lightweight, high-performance cloud-native messaging system. It is used for the communication between the Telestion backend and the Telestion frontend.

      No matter which deployment method you choose, you need to configure NATS. The configuration of NATS is described in the NATS Configuration document.

      ","tags":["Deployment"]},{"location":"Deployment/concepts/","title":"Concepts","text":"

      This document describes the pre-requisites for deploying Telestion on your local machine.

      ","tags":["Deployment"]},{"location":"Deployment/concepts/#docker","title":"Docker","text":"

      Docker is a containerization platform that allows you to package your application and all its dependencies together in the form of containers to ensure that your application works seamlessly in any environment be it development or test or production.

      ","tags":["Deployment"]},{"location":"Deployment/concepts/#docker-compose","title":"Docker Compose","text":"

      Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application\u2019s services. Then, with a single command, you create and start all the services from your configuration.

      ","tags":["Deployment"]},{"location":"Deployment/concepts/#kubernetes","title":"Kubernetes","text":"

      Info

      Kubernetes is not required for deploying Telestion. It\u2019s mostly relevant for big production deployments.

      Kubernetes is an open source container-orchestration system for automating computer application deployment, scaling, and management.

      ","tags":["Deployment"]},{"location":"Deployment/concepts/#web-server","title":"Web Server","text":"

      Info

      For Telestion, a web server is required to serve the frontend application to the user.

      A web server is server software, or hardware dedicated to running said software, that can satisfy web client requests. A web server can, in general, contain one or more websites. A web server processes incoming network requests over HTTP and several other related protocols.

      ","tags":["Deployment"]},{"location":"Deployment/concepts/#nats","title":"NATS","text":"

      Info

      Telestion uses NATS as a message broker. It\u2019s required for the communication between the Telestion services (both backend and frontend).

      NATS is a simple, secure and high-performance open source messaging system for cloud native applications, IoT messaging, and microservice architectures.

      ","tags":["Deployment"]},{"location":"Deployment/docker/","title":"Docker Deployment","text":"

      This document describes how to deploy Telestion using Docker.

      "},{"location":"Deployment/docker/#guidelines","title":"Guidelines","text":"

      These guidelines are not strict rules, but they are recommended to follow. If you have a good reason to deviate from them, feel free to do so. Or in other words: If you don\u2019t know why you should deviate from them, don\u2019t do it.

      "},{"location":"Deployment/docker/#images-per-service-type","title":"Images per Service Type","text":"

      Depending on your project, it might make sense to have individual images for each service. However, for smaller projects, this is often both unnecessary and cumbersome. In this case, it is recommended to have one image for all services of a specific type.

      For example, you would have one image for all Deno based Backend services, one for the frontend, and so on. This way, you won\u2019t have to build and push huge numbers of images, and you can still use the same image for all services of a specific type.

      "},{"location":"Deployment/docker/#dependency-installation-at-build-time","title":"Dependency Installation at Build Time","text":"

      If you have a service that requires dependencies to be installed, it is recommended to do so at build time. This way, you can be sure that the dependencies are installed when the image is built, and you don\u2019t have to wait for them to be installed when the container is started.

      This ensures both a faster startup time and a consistent execution environment.

      "},{"location":"Deployment/kubernetes/","title":"Kubernetes Deployment","text":"

      This document describes how to deploy Telestion using Kubernetes.

      (Work in progress)

      "},{"location":"Deployment/local/","title":"Local Deployment","text":"

      Telestion can be deployed locally on your machine. This can have several reasons, for example:

      • You want to test your application before deploying it to a server
      • You want to develop an application and test it locally
      • You want to run Telestion on a machine without internet connection
      • You want to run Telestion on a machine without Docker/Kubernetes
      • You need to access the machine directly (for example, for CAN bus access)

      Note

      It\u2019s a common tactic to have most Telestion services running in a cloud environment and only the services that need direct access to the machine running locally.

      This is easy to achieve thanks to NATS and means that you can have the best of both worlds.

      ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-nats/","title":"Deploying NATS","text":"

      NATS isn\u2019t complicated to deploy. This guide will show you how to deploy NATS locally.

      ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-nats/#installing-nats","title":"Installing NATS","text":"

      Download the NATS server from the NATS download page.

      ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-nats/#running-nats","title":"Running NATS","text":"

      Run the NATS server with the following command:

      nats-server\n
      ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-nats/#configuring-nats","title":"Configuring NATS","text":"

      NATS can be configured using a configuration file. To run NATS with a configuration file, use the following command:

      nats-server -c <path-to-config-file>\n

      As a starting point, you can use the following configuration to enable everything you need while developing:

      nats.conf
      http_port: 8222\n\nwebsocket: {\n     port: 9222\n     no_tls: true\n}\n

      This will enable the HTTP and WebSocket interfaces.

      Note that for production deployments, you need to configure NATS to use TLS and set up proper authentication. You can learn more about configuring NATS in the NATS configuration guide.

      Learn more about NATS configuration

      ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/","title":"Deploying TypeScript services","text":"","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/#deploying-a-single-service","title":"Deploying a single service","text":"

      (coming soon)

      ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/#deploying-multiple-services-using-the-process-manager-pup","title":"Deploying multiple services using the process manager pup","text":"

      The process manager pup is a tool that can be used to run multiple services at once without having to manually start each service. It also makes it easy to manage the running services.

      ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/#installing-pup","title":"Installing pup","text":"

      Install pup using the following command:

      deno install -Afr https://deno.land/x/pup/pup.ts\n
      ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/#configuring-pup","title":"Configuring pup","text":"

      In your project\u2019s root directory, create a file called pup.jsonc with the following contents:

      {\n  \"services\": [\n    {\n      \"name\": \"service1\",\n      \"command\": \"deno run --allow-net --allow-env service1.ts\",\n      \"env\": {\n        \"SERVICE_NAME\": \"service1\",\n        \"NATS_URL\": \"nats://localhost:4222\",\n        \"NATS_USER\": \"service\",\n        \"NATS_PASSWORD\": \"service\"\n      }\n    },\n    {\n      \"name\": \"service2\",\n      \"command\": \"deno run --allow-net --allow-env service2.ts\",\n      \"env\": {\n        \"SERVICE_NAME\": \"service1\",\n        \"NATS_URL\": \"nats://localhost:4222\",\n        \"NATS_USER\": \"service\",\n        \"NATS_PASSWORD\": \"service\"\n      }\n    }\n  ]\n}\n
      ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/#running-pup","title":"Running pup","text":"

      Run pup using the following command:

      pup -c pup.jsonc run\n

      This will start the pup runner. To start the services, run the following command:

      pup -c pup.jsonc start all\n

      Tip

      If you want to have a service starting immediately after the runner starts, you can add \"autostart\": true to that service\u2019s configuration.

      To stop the services, run the following command:

      pup -c pup.jsonc stop all\n

      Tip

      You can also stop a single service by specifying its name instead of all.

      You can get the status of the services using the following command:

      pup -c pup.jsonc status\n

      Tip: Running NATS through pup

      You can even run NATS through pup. Just add the following service to your pup.jsonc file:

      {\n  \"name\": \"nats\",\n  \"command\": \"nats-server -c <path-to-config-file>\",\n  \"env\": {}\n}\n

      You can find more information about pup on their documentation page.

      ","tags":["Deployment","Local"]},{"location":"Deployment/nats/","title":"NATS Server Configuration","text":"

      The NATS server can be configured using both a configuration file and environment variables.

      "},{"location":"Deployment/nats/#environment-variables","title":"Environment Variables","text":"

      The NATS server configuration is done via environment variables. The following table lists all available environment variables and their default values.

      Environment Variable Default Value Description NATS_HOST localhost The host of the NATS server. NATS_PORT 4222 The port of the NATS server."},{"location":"Deployment/nats/#configuration-file","title":"Configuration File","text":"

      The NATS server can also be configured using a configuration file. To use a configuration file, you need to pass the -c flag to the NATS server:

      nats-server -c <path-to-config-file>\n

      You can find a full reference of the NATS server configuration in the NATS documentation.

      For Telestion, the following settings are of special interest:

      1. websocket - This section configures the WebSocket interface of the NATS server. It\u2019s used by the Telestion frontend to connect to the NATS server.
      2. authorization - This section configures who can publish and subscribe to which subjects.
      3. authorization.users - This section configures the user accounts that can connect to the NATS server. It\u2019s used to configure the user accounts that can connect to the NATS server. As of right now, Telestion exclusively supports username/password-based authentication.
      "},{"location":"Deployment/nats/#development-configuration","title":"Development Configuration","text":"

      The following configuration is a good starting point for development.

      Danger

      Do not use this configuration in production! It\u2019s only meant for development.

      There are several problems with this configuration that make it unsuitable for production:

      1. it doesn\u2019t use TLS for the websocket interface, meaning that all communication is unencrypted
      2. it doesn\u2019t have any authentication or authorization configured, meaning that anyone can connect to the NATS server and publish/subscribe to any subject

      In essence, if you were to use this configuration in production, you would have a NATS server that is publicly accessible and allows anyone with access to your server to publish/subscribe to any subject!

      nats.conf
      http_port: 8222\n\nwebsocket: {\n    port: 9222\n    no_tls: true\n}\n
      "},{"location":"Frontend%20Development/","title":"Frontend","text":"

      Processing data is only half the fun. To make the data accessible to the user, you need a frontend.

      Telestion uses a frontend based on React, TypeScript, and Bootstrap. Thankfully, Telestion (together with vite) provides a lot of tools to make frontend development as easy as possible.

      All you need to get started is an installation of Node.js and pnpm.

      "},{"location":"Frontend%20Development/#creating-a-new-frontend","title":"Creating a new Frontend","text":"

      To create a new frontend, create a new directory for it:

      mkdir telestion-frontend && cd telestion-frontend\n

      Now, add the following files to your directory:

      "},{"location":"Frontend%20Development/#packagejson","title":"package.json","text":"
      {\n  \"name\": \"telestion-frontend\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@wuespace/telestion\": \"^1.0.0-alpha.2\",// (1)!\n    \"react\": \"^18.2.0\",\n    \"zod\": \"^3.22.4\"// (2)!\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react-swc\": \"^3.5.0\",\n    \"vite\": \"^5.0.8\"\n  }\n}\n
      1. Add the @wuespace/telestion package as a dependency. This package contains all the tools you need to get started with frontend development.
      2. Add the zod package as a dependency. This package is used to validate any data that is sent to the frontend.
      "},{"location":"Frontend%20Development/#viteconfigts","title":"vite.config.ts","text":"
      import { defineConfig } from \"vite\";\nimport react from '@vitejs/plugin-react-swc';\n\nexport default defineConfig({\n  plugins: [react()/*(1)!*/],\n});\n
      1. Add the react plugin to vite. This plugin allows you to use React in your frontend.
      "},{"location":"Frontend%20Development/#indexhtml","title":"index.html","text":"
      <!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Telestion Frontend</title>\n  </head>\n  <body data-bs-theme=\"dark\"><!-- (1)! -->\n    <div id=\"root\"></div><!-- (2)! -->\n    <script type=\"module\" src=\"/index.ts\"></script><!-- (3)! -->\n  </body>\n</html>\n
      1. Add the data-bs-theme attribute to the body tag. This attribute is used to set the default theme of the frontend. You can choose between light and dark.
      2. Add a div tag with the id root. This is where your frontend will be rendered.
      3. Add a script tag that loads the index.ts file. This file is the entry point of your frontend.
      "},{"location":"Frontend%20Development/#indexts","title":"index.ts","text":"
      import { initTelestion, registerWidgets } from \"@wuespace/telestion\"; // (1)!\n\nimport \"@wuespace/telestion/telestion.css\"; // (2)!\n\n// initialize Telestion\nawait initTelestion/* (3)!*/({\n  version: \"1.0.0\",// (4)!\n});\n\n// register your widget in Telestion\n// registerWidgets(...);// (5)! \n
      1. Import the initTelestion and registerWidgets functions from the @wuespace/telestion package.
      2. Import the telestion.css file from the @wuespace/telestion package. This file contains all the styles (including all Bootstrap styles) you need to get started with frontend development.
      3. Initialize Telestion. This sets up a basic frontend including authentication, dashboards, etc.
      4. Set the version of your frontend. This is used to check if the user data needs to be migrated.
      5. Register your widgets in Telestion. This is explained in more detail in the next section.
      "},{"location":"Frontend%20Development/#installing-dependencies","title":"Installing Dependencies","text":"

      To install the dependencies, run the following command:

      pnpm install\n
      "},{"location":"Frontend%20Development/#running-the-frontend","title":"Running the Frontend","text":"

      To run the frontend, run the following command:

      pnpm dlx vite\n

      This will start a development server on port 5173. You can now open your browser and navigate to http://localhost:5173.

      "},{"location":"Frontend%20Development/#building-the-frontend","title":"Building the Frontend","text":"

      To build the frontend, run the following command:

      pnpm dlx vite build\n
      "},{"location":"Frontend%20Development/#next-steps","title":"Next Steps","text":"

      Now that you have a basic frontend running, you should have a look at how to add widgets to it.

      "},{"location":"Frontend%20Development/concepts/","title":"Concepts","text":"

      This document describes the various concepts you need to know when building components for the Telestion frontend.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#overview","title":"Overview","text":"

      You can find the most important concepts of the Telestion frontend as well as how they relate to each other in the following diagram:

      graph BT\n  frontend[Telestion Frontend] -->|is written in|react[React]\n  react -->|uses the programming language|ts[TypeScript]\n  user[User] -->|uses|frontend\n  subgraph frontend[Telestion Frontend]\n    dashboard[Dashboard]\n    widgetInstance[Widget Instances]\n    widget[Widgets]\n  end\n  dashboard[Dashboard] -->|is a layout of|widgetInstance[Widget Instances]\n  widget -->|defines the look and behavior of|widgetInstance[Widget Instances]\n  click widgetInstance \"#widget-instances\" \"Widget Instance\"\n  click widget \"#widget\" \"Widget\"\n  click dashboard \"#dashboard\" \"Dashboard\"\n  click react \"#react\" \"React\"\n  click ts \"#typescript\" \"TypeScript\"

      You can click on the elements in the diagram to learn more about them.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#frontend","title":"Frontend","text":"

      The Telestion frontend is the part of Telestion that is visible to the user. It is built with React and TypeScript. It is responsible for displaying data from the backend and for sending commands to the backend.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#dashboard","title":"Dashboard","text":"

      A dashboard is a layout of widget instances with a specific configuration, created by the user. They are the main part of the Telestion frontend.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#widget-instances","title":"Widget Instances","text":"

      A widget instance is an instance of a widget with a specific configuration. They are the building blocks of dashboards.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#widget","title":"Widget","text":"

      A widget is the type of a widget instance. It contains the code that defines how the widget instance looks like and how it behaves.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#htmlcssjavascript","title":"HTML/CSS/JavaScript","text":"

      HTML, CSS, and JavaScript are the three core technologies of the web. HTML is used to describe the structure of web pages. CSS is used to describe the presentation of web pages. JavaScript is used to describe the behavior of web pages.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#react","title":"React","text":"

      The Telestion frontend is built with React. React is a JavaScript library for building user interfaces. It is component-based and declarative. This means that you can build your UI from small, reusable components and that you can describe how your UI should look like without having to worry about how it is rendered.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#components","title":"Components","text":"

      Components are the building blocks of React applications. They are small, reusable pieces of code that can be composed to build more complex components. Components can be either functional or class-based. Functional components are just functions that return a React element.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#jsx","title":"JSX","text":"

      JSX is a syntax extension to JavaScript that allows you to write HTML-like code in your JavaScript files. It is not required to use JSX when writing React applications, but it is recommended. JSX makes your code more readable and easier to write. It also allows you to use the full power of JavaScript inside your HTML-like code.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#props","title":"Props","text":"

      Props are the way to pass data from a parent component to a child component. They are immutable and can only be changed by the parent component. Props are passed to a component as attributes in JSX.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#state","title":"State","text":"

      State is the way to store data inside a component. It is mutable and can be changed by the component itself.

      You can initialize and use state using the useState() hook like this:

      const [counter, setCounter] = useState(0); // initialize with 0\nsetCounter(counter + 1); // increase counter by 1\n
      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#hooks","title":"Hooks","text":"

      Hooks are a new feature that was introduced in React 16.8. They allow you to use state and other React features without writing a class. Hooks are functions that can be called inside functional components. They allow you to use state and other React features without writing a class.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#typescript","title":"TypeScript","text":"

      The Telestion frontend is written in TypeScript. TypeScript is a superset of JavaScript that adds static typing to the language. It is a strict superset of JavaScript, which means that any valid JavaScript code is also valid TypeScript code. TypeScript is a statically typed language, which means that the type of a variable is known at compile time. This allows the compiler to catch many errors at compile time instead of at runtime.

      ","tags":["Frontend Development"]},{"location":"Frontend%20Development/api/","title":"Index","text":""},{"location":"Frontend%20Development/api/#modules","title":"Modules","text":"
      • application
      • auth
      • index
      • nats
      • user-data
      • utils
      • widget
      "},{"location":"Frontend%20Development/api/application/","title":"Index","text":"

      @wuespace/telestion / application

      This package provides the main entry point for the Telestion frontend application.

      You can initialize the application by calling the initTelestion function.

      "},{"location":"Frontend%20Development/api/application/#example","title":"Example","text":"
      import { initTelestion } from '@wuespace/telestion/application';\n// or, for convenience:\n// import { initTelestion } from '@wuespace/telestion';\n\ninitTelestion({ ... });\n
      "},{"location":"Frontend%20Development/api/application/#functions","title":"Functions","text":"
      • initTelestion
      "},{"location":"Frontend%20Development/api/application/#references","title":"References","text":""},{"location":"Frontend%20Development/api/application/#telestionoptions","title":"TelestionOptions","text":"

      Re-exports TelestionOptions

      "},{"location":"Frontend%20Development/api/application/#usewidgetconfig","title":"useWidgetConfig","text":"

      Re-exports useWidgetConfig

      "},{"location":"Frontend%20Development/api/application/functions/initTelestion/","title":"initTelestion","text":"

      @wuespace/telestion / application / initTelestion

      initTelestion(options): Promise<void>

      Initialize the Telestion application.

      "},{"location":"Frontend%20Development/api/application/functions/initTelestion/#parameters","title":"Parameters","text":"

      \u2022 options: TelestionOptions

      The options for initializing the application.

      "},{"location":"Frontend%20Development/api/application/functions/initTelestion/#returns","title":"Returns","text":"

      Promise<void>

      A Promise that resolves once the initialization is completed.

      "},{"location":"Frontend%20Development/api/auth/","title":"Index","text":"

      @wuespace/telestion / auth

      Functions and types relating to the authentication of users in the Telestion frontend.

      Note that in most cases, you don\u2019t need to import anything from this package directly, since auth*n is already handled by the framework itself.

      "},{"location":"Frontend%20Development/api/auth/#example","title":"Example","text":"
      import { ... } from '@wuespace/telestion/auth';\n
      "},{"location":"Frontend%20Development/api/auth/#classes","title":"Classes","text":"
      • LoginError
      "},{"location":"Frontend%20Development/api/auth/#interfaces","title":"Interfaces","text":"
      • ErrorMessages
      • User
      "},{"location":"Frontend%20Development/api/auth/#functions","title":"Functions","text":"
      • attemptAutoLogin
      • getNatsConnection
      • getUser
      • isLoggedIn
      • login
      • logout
      • setAutoLoginCredentials
      • setNatsConnection
      • setUser
      • useNatsSubscription
      "},{"location":"Frontend%20Development/api/auth/#references","title":"References","text":""},{"location":"Frontend%20Development/api/auth/#usenats","title":"useNats","text":"

      Re-exports useNats

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/","title":"LoginError","text":"

      @wuespace/telestion / auth / LoginError

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#extends","title":"Extends","text":"
      • Error
      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#constructors","title":"Constructors","text":""},{"location":"Frontend%20Development/api/auth/classes/LoginError/#new-loginerrormessages","title":"new LoginError(messages)","text":"

      new LoginError(messages): LoginError

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#parameters","title":"Parameters","text":"

      \u2022 messages: ErrorMessages

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#returns","title":"Returns","text":"

      LoginError

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#overrides","title":"Overrides","text":"

      Error.constructor

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/auth/classes/LoginError/#message","title":"message","text":"

      message: string

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from","title":"Inherited from","text":"

      Error.message

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#messages","title":"messages","text":"

      messages: ErrorMessages

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#name","title":"name","text":"

      name: string

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from_1","title":"Inherited from","text":"

      Error.name

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#stack","title":"stack?","text":"

      stack?: string

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from_2","title":"Inherited from","text":"

      Error.stack

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#preparestacktrace","title":"prepareStackTrace?","text":"

      static prepareStackTrace?: (err, stackTraces) => any

      Optional override for formatting stack traces

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#parameters_1","title":"Parameters","text":"

      \u2022 err: Error

      \u2022 stackTraces: CallSite[]

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#returns_1","title":"Returns","text":"

      any

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#see","title":"See","text":"

      https://v8.dev/docs/stack-trace-api#customizing-stack-traces

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from_3","title":"Inherited from","text":"

      Error.prepareStackTrace

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#stacktracelimit","title":"stackTraceLimit","text":"

      static stackTraceLimit: number

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from_4","title":"Inherited from","text":"

      Error.stackTraceLimit

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/auth/classes/LoginError/#capturestacktrace","title":"captureStackTrace()","text":"

      static captureStackTrace(targetObject, constructorOpt?): void

      Create .stack property on a target object

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#parameters_2","title":"Parameters","text":"

      \u2022 targetObject: object

      \u2022 constructorOpt?: Function

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#returns_2","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from_5","title":"Inherited from","text":"

      Error.captureStackTrace

      "},{"location":"Frontend%20Development/api/auth/functions/attemptAutoLogin/","title":"attemptAutoLogin","text":"

      @wuespace/telestion / auth / attemptAutoLogin

      attemptAutoLogin(): Promise<boolean>

      Attempt to auto-login using credentials stored in sessionStorage.

      The credentials will automatically be cleared if they are invalid, the session ends, or logout is called.

      Credentials are automatically stored updated by login and logout.

      "},{"location":"Frontend%20Development/api/auth/functions/attemptAutoLogin/#returns","title":"Returns","text":"

      Promise<boolean>

      true if auto-login was successful, false otherwise

      "},{"location":"Frontend%20Development/api/auth/functions/getNatsConnection/","title":"getNatsConnection","text":"

      @wuespace/telestion / auth / getNatsConnection

      getNatsConnection(): null | NatsConnection

      "},{"location":"Frontend%20Development/api/auth/functions/getNatsConnection/#returns","title":"Returns","text":"

      null | NatsConnection

      "},{"location":"Frontend%20Development/api/auth/functions/getUser/","title":"getUser","text":"

      @wuespace/telestion / auth / getUser

      getUser(): null | User

      Returns the user object if the user is currently logged in, else returns null if no user is currently logged in.

      "},{"location":"Frontend%20Development/api/auth/functions/getUser/#returns","title":"Returns","text":"

      null | User

      "},{"location":"Frontend%20Development/api/auth/functions/isLoggedIn/","title":"isLoggedIn","text":"

      @wuespace/telestion / auth / isLoggedIn

      isLoggedIn(): boolean

      Checks if a user is logged in.

      "},{"location":"Frontend%20Development/api/auth/functions/isLoggedIn/#returns","title":"Returns","text":"

      boolean

      true if the user is logged in, false otherwise.

      "},{"location":"Frontend%20Development/api/auth/functions/login/","title":"Login","text":"

      @wuespace/telestion / auth / login

      login(natsUrl, username, password): Promise<null | User>

      Logs in a user with the given credentials.

      "},{"location":"Frontend%20Development/api/auth/functions/login/#parameters","title":"Parameters","text":"

      \u2022 natsUrl: string

      The url to connect to the NATS server.

      \u2022 username: string

      The username for authentication.

      \u2022 password: string

      The password for authentication.

      "},{"location":"Frontend%20Development/api/auth/functions/login/#returns","title":"Returns","text":"

      Promise<null | User>

      A promise that resolves once the user is logged in. The resolved value is the logged-in user object.

      "},{"location":"Frontend%20Development/api/auth/functions/login/#throws","title":"Throws","text":"

      Error If the provided credentials are incorrect.

      "},{"location":"Frontend%20Development/api/auth/functions/logout/","title":"Logout","text":"

      @wuespace/telestion / auth / logout

      logout(): Promise<void>

      Logs out the user if currently logged in.

      "},{"location":"Frontend%20Development/api/auth/functions/logout/#returns","title":"Returns","text":"

      Promise<void>

      A promise that resolves once the user is logged out.

      "},{"location":"Frontend%20Development/api/auth/functions/setAutoLoginCredentials/","title":"setAutoLoginCredentials","text":"

      @wuespace/telestion / auth / setAutoLoginCredentials

      setAutoLoginCredentials(credentials): void

      Sets credentials with which to auto-login.

      If an auto-login attempt fails, the credentials will be cleared for the remainder of the session and a login form shown to the user. If the user logs in successfully, the credentials will be updated.

      "},{"location":"Frontend%20Development/api/auth/functions/setAutoLoginCredentials/#security-warning","title":"Security Warning","text":"

      Use this function only if user authentication is handled by a separate system. Calling this function in your application means your NATS credentials will be hard-coded into your application, which is a security risk.

      "},{"location":"Frontend%20Development/api/auth/functions/setAutoLoginCredentials/#parameters","title":"Parameters","text":"

      \u2022 credentials: Object

      The credentials to store

      \u2022 credentials.natsUrl: string= undefined

      The URL of the NATS server to connect to.

      \u2022 credentials.password: string= undefined

      The password to use when connecting to the NATS server.

      \u2022 credentials.username: string= undefined

      The username to use when connecting to the NATS server.

      "},{"location":"Frontend%20Development/api/auth/functions/setAutoLoginCredentials/#returns","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/auth/functions/setAutoLoginCredentials/#deprecated","title":"Deprecated","text":"

      No, this won\u2019t be removed anytime soon. You can ignore this warning if you\u2019re aware of the security implications.

      "},{"location":"Frontend%20Development/api/auth/functions/setNatsConnection/","title":"setNatsConnection","text":"

      @wuespace/telestion / auth / setNatsConnection

      setNatsConnection(nc): void

      "},{"location":"Frontend%20Development/api/auth/functions/setNatsConnection/#parameters","title":"Parameters","text":"

      \u2022 nc: null | NatsConnection

      "},{"location":"Frontend%20Development/api/auth/functions/setNatsConnection/#returns","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/auth/functions/setUser/","title":"setUser","text":"

      @wuespace/telestion / auth / setUser

      setUser(user): void

      Sets a new user object or null if the user is no longer logged in.

      "},{"location":"Frontend%20Development/api/auth/functions/setUser/#parameters","title":"Parameters","text":"

      \u2022 user: null | User

      the user object or null

      "},{"location":"Frontend%20Development/api/auth/functions/setUser/#returns","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/auth/functions/useNatsSubscription/","title":"useNatsSubscription","text":"

      @wuespace/telestion / auth / useNatsSubscription

      useNatsSubscription(subject, callback, options?): void

      "},{"location":"Frontend%20Development/api/auth/functions/useNatsSubscription/#parameters","title":"Parameters","text":"

      \u2022 subject: string

      \u2022 callback: (message) => void | Promise<void>

      \u2022 options?: SubscriptionOptions

      "},{"location":"Frontend%20Development/api/auth/functions/useNatsSubscription/#returns","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/auth/interfaces/ErrorMessages/","title":"ErrorMessages","text":"

      @wuespace/telestion / auth / ErrorMessages

      "},{"location":"Frontend%20Development/api/auth/interfaces/ErrorMessages/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/auth/interfaces/ErrorMessages/#natsurlmessage","title":"natsUrlMessage?","text":"

      natsUrlMessage?: string

      "},{"location":"Frontend%20Development/api/auth/interfaces/ErrorMessages/#passwordmessage","title":"passwordMessage?","text":"

      passwordMessage?: string

      "},{"location":"Frontend%20Development/api/auth/interfaces/ErrorMessages/#usernamemessage","title":"usernameMessage?","text":"

      usernameMessage?: string

      "},{"location":"Frontend%20Development/api/auth/interfaces/User/","title":"User","text":"

      @wuespace/telestion / auth / User

      A logged-in user.

      "},{"location":"Frontend%20Development/api/auth/interfaces/User/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/auth/interfaces/User/#natsurl","title":"natsUrl","text":"

      natsUrl: string

      The NATS URL that the user is connected to.

      "},{"location":"Frontend%20Development/api/auth/interfaces/User/#username","title":"username","text":"

      username: string

      The user\u2019s username.

      "},{"location":"Frontend%20Development/api/index/","title":"Index","text":"

      @wuespace/telestion / index

      The Telestion Frontend Library.

      Import this library to use the Telestion Frontend:

      import { initTelestion } from '@wuespace/telestion';\n

      The most important function is initTelestion. It initializes the Telestion Frontend and renders the application.

      initTelestion({\n  version: '1.0.0',\n  ...\n});\n
      "},{"location":"Frontend%20Development/api/index/#see","title":"See","text":"

      initTelestion

      "},{"location":"Frontend%20Development/api/index/#interfaces","title":"Interfaces","text":"
      • TelestionOptions
      • Widget
      "},{"location":"Frontend%20Development/api/index/#type-aliases","title":"Type Aliases","text":"
      • UserData
      "},{"location":"Frontend%20Development/api/index/#functions","title":"Functions","text":"
      • JSONCodec
      • registerWidgets
      • useNats
      • useWidgetConfig
      "},{"location":"Frontend%20Development/api/index/#references","title":"References","text":""},{"location":"Frontend%20Development/api/index/#inittelestion","title":"initTelestion","text":"

      Re-exports initTelestion

      "},{"location":"Frontend%20Development/api/index/functions/JSONCodec/","title":"JSONCodec","text":"

      @wuespace/telestion / index / JSONCodec

      JSONCodec<T>(reviver?): Codec<T>

      Returns a Codec for encoding JavaScript object to JSON and serialize them to an Uint8Array, and conversely, from an Uint8Array to JSON to a JavaScript Object.

      "},{"location":"Frontend%20Development/api/index/functions/JSONCodec/#type-parameters","title":"Type parameters","text":"

      \u2022 T = unknown

      "},{"location":"Frontend%20Development/api/index/functions/JSONCodec/#parameters","title":"Parameters","text":"

      \u2022 reviver?: (this, key, value) => unknown

      "},{"location":"Frontend%20Development/api/index/functions/JSONCodec/#returns","title":"Returns","text":"

      Codec<T>

      "},{"location":"Frontend%20Development/api/index/functions/registerWidgets/","title":"registerWidgets","text":"

      @wuespace/telestion / index / registerWidgets

      registerWidgets(\u2026widgets): void

      Registers widgets in the widget store.

      If a widget with the same ID already exists in the widget store, a warning is logged and the widget is ignored.

      "},{"location":"Frontend%20Development/api/index/functions/registerWidgets/#parameters","title":"Parameters","text":"

      \u2022 \u2026widgets: Widget<Record<string, unknown>>[]

      The widgets to be registered.

      "},{"location":"Frontend%20Development/api/index/functions/registerWidgets/#returns","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/index/functions/useNats/","title":"useNats","text":"

      @wuespace/telestion / index / useNats

      useNats(): NatsConnection

      "},{"location":"Frontend%20Development/api/index/functions/useNats/#returns","title":"Returns","text":"

      NatsConnection

      "},{"location":"Frontend%20Development/api/index/functions/useWidgetConfig/","title":"useWidgetConfig","text":"

      @wuespace/telestion / index / useWidgetConfig

      useWidgetConfig<T>(): T

      Retrieves the widget configuration from the widgetConfigContext.

      "},{"location":"Frontend%20Development/api/index/functions/useWidgetConfig/#type-parameters","title":"Type parameters","text":"

      \u2022 T

      The type of the widget configuration.

      "},{"location":"Frontend%20Development/api/index/functions/useWidgetConfig/#returns","title":"Returns","text":"

      T

      The widget configuration retrieved from the widgetConfigContext.

      "},{"location":"Frontend%20Development/api/index/functions/useWidgetConfig/#throws","title":"Throws","text":"

      Error Throws an error if useWidgetConfig is not used within a WidgetConfigProvider.

      "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/","title":"TelestionOptions","text":"

      @wuespace/telestion / index / TelestionOptions

      Represents the options for Telestion.

      "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#defaultbackendurl","title":"defaultBackendUrl?","text":"

      defaultBackendUrl?: string

      The backend URL that should be inserted by default on first page load.

      "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#defaultuserdata","title":"defaultUserData?","text":"

      defaultUserData?: Object

      Represents the default user data.

      "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#type-declaration","title":"Type declaration","text":""},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#dashboards","title":"dashboards","text":"

      dashboards: Record<string, { title: string; layout: string[][]; }>

      The user\u2019s dashboards.

      "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#version","title":"version","text":"

      version: string

      The version of the client that created this user data.

      "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#widgetinstances","title":"widgetInstances","text":"

      widgetInstances: Record<string, { type: string; configuration: Record<string, unknown>; }>

      The user\u2019s widget instances.

      "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#version_1","title":"version","text":"

      version: string

      Represents the current version of the software.

      "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#widgets","title":"widgets?","text":"

      widgets?: Widget<Record<string, unknown>>[]

      Represents an array of widgets.

      "},{"location":"Frontend%20Development/api/index/interfaces/Widget/","title":"Widget","text":"

      @wuespace/telestion / index / Widget

      A widget that can be used in widget instances on dashboards.

      "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#see","title":"See","text":"

      userData.WidgetInstance

      "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#type-parameters","title":"Type parameters","text":"

      \u2022 T extends Record<string, unknown> = Record<string, unknown>

      the type of the widget configuration

      "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/index/interfaces/Widget/#configelement","title":"configElement","text":"

      configElement: ReactNode

      A configuration element that is used to configure the widget.

      "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#element","title":"element","text":"

      element: ReactNode

      A function that takes the configuration of the widget and returns a React element that represents the widget.

      "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#id","title":"id","text":"

      id: string

      Represents an identifier of the widget type.

      "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#label","title":"label","text":"

      label: string

      Represents a human-readable label of the widget type.

      "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/index/interfaces/Widget/#createconfig","title":"createConfig()","text":"

      createConfig(input): T

      A function that takes an object that contains the previous widget configuration (which may or may not be from a previous version of the client (or could also, when creating new widget instances, be empty) and returns a valid configuration for the widget.

      For widgets with expected breaking changes, it is therefore useful to have some version identifier be a part of the configuration options to enable more complex migration logic in this function.

      "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#parameters","title":"Parameters","text":"

      \u2022 input: Partial<T> & Record<string, unknown>

      previous configuration or empty

      "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#returns","title":"Returns","text":"

      T

      "},{"location":"Frontend%20Development/api/index/type-aliases/UserData/","title":"UserData","text":"

      @wuespace/telestion / index / UserData

      UserData: Object

      Represents the user data.

      "},{"location":"Frontend%20Development/api/index/type-aliases/UserData/#see","title":"See","text":"

      userDataSchema

      "},{"location":"Frontend%20Development/api/index/type-aliases/UserData/#type-declaration","title":"Type declaration","text":""},{"location":"Frontend%20Development/api/index/type-aliases/UserData/#dashboards","title":"dashboards","text":"

      dashboards: Record<string, { title: string; layout: string[][]; }>

      The user\u2019s dashboards.

      "},{"location":"Frontend%20Development/api/index/type-aliases/UserData/#version","title":"version","text":"

      version: string

      The version of the client that created this user data.

      "},{"location":"Frontend%20Development/api/index/type-aliases/UserData/#widgetinstances","title":"widgetInstances","text":"

      widgetInstances: Record<string, { type: string; configuration: Record<string, unknown>; }>

      The user\u2019s widget instances.

      "},{"location":"Frontend%20Development/api/nats/","title":"Index","text":"

      @wuespace/telestion / nats

      Re-exporting the most used types and functions from the nats.ws package.

      "},{"location":"Frontend%20Development/api/nats/#example","title":"Example","text":"
      import { Msg, JSONCodec, ... } from '@wuespace/telestion/nats';\n
      "},{"location":"Frontend%20Development/api/nats/#see","title":"See","text":"
      • https://docs.nats.io/using-nats/developer
      • https://github.com/nats-io/nats.ws#readme
      "},{"location":"Frontend%20Development/api/nats/#classes","title":"Classes","text":"
      • NatsError
      "},{"location":"Frontend%20Development/api/nats/#interfaces","title":"Interfaces","text":"
      • Codec
      • Msg
      • MsgHdrs
      • NatsConnection
      • PublishOptions
      • RequestOptions
      • Sub
      • SubOpts
      "},{"location":"Frontend%20Development/api/nats/#type-aliases","title":"Type Aliases","text":"
      • MsgRequest
      • Subscription
      • SubscriptionOptions
      "},{"location":"Frontend%20Development/api/nats/#functions","title":"Functions","text":"
      • StringCodec
      • headers
      "},{"location":"Frontend%20Development/api/nats/#references","title":"References","text":""},{"location":"Frontend%20Development/api/nats/#jsoncodec","title":"JSONCodec","text":"

      Re-exports JSONCodec

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/","title":"NatsError","text":"

      @wuespace/telestion / nats / NatsError

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#extends","title":"Extends","text":"
      • Error
      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#constructors","title":"Constructors","text":""},{"location":"Frontend%20Development/api/nats/classes/NatsError/#new-natserrormessage-code-chainederror","title":"new NatsError(message, code, chainedError)","text":"

      new NatsError(message, code, chainedError?): NatsError

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#parameters","title":"Parameters","text":"

      \u2022 message: string

      \u2022 code: string

      \u2022 chainedError?: Error

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns","title":"Returns","text":"

      NatsError

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#overrides","title":"Overrides","text":"

      Error.constructor

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#api","title":"Api","text":"

      private

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/classes/NatsError/#api_error","title":"api_error?","text":"

      api_error?: ApiError

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#chainederror","title":"chainedError?","text":"

      chainedError?: Error

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#code","title":"code","text":"

      code: string

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#message","title":"message","text":"

      message: string

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#overrides_1","title":"Overrides","text":"

      Error.message

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#name","title":"name","text":"

      name: string

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#overrides_2","title":"Overrides","text":"

      Error.name

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#permissioncontext","title":"permissionContext?","text":"

      permissionContext?: Object

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#type-declaration","title":"Type declaration","text":""},{"location":"Frontend%20Development/api/nats/classes/NatsError/#operation","title":"operation","text":"

      operation: string

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#subject","title":"subject","text":"

      subject: string

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#stack","title":"stack?","text":"

      stack?: string

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#inherited-from","title":"Inherited from","text":"

      Error.stack

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#preparestacktrace","title":"prepareStackTrace?","text":"

      static prepareStackTrace?: (err, stackTraces) => any

      Optional override for formatting stack traces

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#parameters_1","title":"Parameters","text":"

      \u2022 err: Error

      \u2022 stackTraces: CallSite[]

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_1","title":"Returns","text":"

      any

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#see","title":"See","text":"

      https://v8.dev/docs/stack-trace-api#customizing-stack-traces

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#inherited-from_1","title":"Inherited from","text":"

      Error.prepareStackTrace

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#stacktracelimit","title":"stackTraceLimit","text":"

      static stackTraceLimit: number

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#inherited-from_2","title":"Inherited from","text":"

      Error.stackTraceLimit

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/classes/NatsError/#isautherror","title":"isAuthError()","text":"

      isAuthError(): boolean

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_2","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#isauthtimeout","title":"isAuthTimeout()","text":"

      isAuthTimeout(): boolean

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_3","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#isjetstreamerror","title":"isJetStreamError()","text":"

      isJetStreamError(): boolean

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_4","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#ispermissionerror","title":"isPermissionError()","text":"

      isPermissionError(): boolean

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_5","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#isprotocolerror","title":"isProtocolError()","text":"

      isProtocolError(): boolean

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_6","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#jserror","title":"jsError()","text":"

      jsError(): null | ApiError

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_7","title":"Returns","text":"

      null | ApiError

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#capturestacktrace","title":"captureStackTrace()","text":"

      static captureStackTrace(targetObject, constructorOpt?): void

      Create .stack property on a target object

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#parameters_2","title":"Parameters","text":"

      \u2022 targetObject: object

      \u2022 constructorOpt?: Function

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_8","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#inherited-from_3","title":"Inherited from","text":"

      Error.captureStackTrace

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#errorforcode","title":"errorForCode()","text":"

      static errorForCode(code, chainedError?): NatsError

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#parameters_3","title":"Parameters","text":"

      \u2022 code: string

      \u2022 chainedError?: Error

      "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_9","title":"Returns","text":"

      NatsError

      "},{"location":"Frontend%20Development/api/nats/functions/StringCodec/","title":"StringCodec","text":"

      @wuespace/telestion / nats / StringCodec

      StringCodec(): Codec<string>

      Returns a Codec for encoding strings to a message payload and decoding message payloads into strings.

      "},{"location":"Frontend%20Development/api/nats/functions/StringCodec/#returns","title":"Returns","text":"

      Codec<string>

      "},{"location":"Frontend%20Development/api/nats/functions/headers/","title":"Headers","text":"

      @wuespace/telestion / nats / headers

      headers(code?, description?): MsgHdrs

      "},{"location":"Frontend%20Development/api/nats/functions/headers/#parameters","title":"Parameters","text":"

      \u2022 code?: number

      \u2022 description?: string

      "},{"location":"Frontend%20Development/api/nats/functions/headers/#returns","title":"Returns","text":"

      MsgHdrs

      "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/","title":"Codec","text":"

      @wuespace/telestion / nats / Codec

      "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#type-parameters","title":"Type parameters","text":"

      \u2022 T

      "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#decode","title":"decode()","text":"

      decode(a): T

      Decode an Uint8Array from a message payload into a T

      "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#parameters","title":"Parameters","text":"

      \u2022 a: Uint8Array

      "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#returns","title":"Returns","text":"

      T

      "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#encode","title":"encode()","text":"

      encode(d): Uint8Array

      Encode T to an Uint8Array suitable for including in a message payload.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#parameters_1","title":"Parameters","text":"

      \u2022 d: T

      "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#returns_1","title":"Returns","text":"

      Uint8Array

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/","title":"Msg","text":"

      @wuespace/telestion / nats / Msg

      Represents a message delivered by NATS. This interface is used by Subscribers.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#data","title":"data","text":"

      data: Uint8Array

      The message\u2019s data (or payload)

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#headers","title":"headers?","text":"

      headers?: MsgHdrs

      Possible headers that may have been set by the server or the publisher.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#reply","title":"reply?","text":"

      reply?: string

      A possible subject where the recipient may publish a reply (in the cases where the message represents a request).

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#sid","title":"sid","text":"

      sid: number

      The subscription ID where the message was dispatched.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#subject","title":"subject","text":"

      subject: string

      The subject the message was sent to

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#json","title":"json()","text":"

      json<T>(reviver?): T

      Convenience method to parse the message payload as JSON. This method will throw an exception if there\u2019s a parsing error;

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#type-parameters","title":"Type parameters","text":"

      \u2022 T

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#parameters","title":"Parameters","text":"

      \u2022 reviver?: ReviverFn

      a reviver function

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#returns","title":"Returns","text":"

      T

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#respond","title":"respond()","text":"

      respond(payload?, opts?): boolean

      Convenience to publish a response to the reply subject in the message - this is the same as doing nc.publish(msg.reply, ...).

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#parameters_1","title":"Parameters","text":"

      \u2022 payload?: Payload

      \u2022 opts?: PublishOptions

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#returns_1","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#string","title":"string()","text":"

      string(): string

      Convenience method to parse the message payload as string. This method may throw an exception if there\u2019s a conversion error

      "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#returns_2","title":"Returns","text":"

      string

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/","title":"MsgHdrs","text":"

      @wuespace/telestion / nats / MsgHdrs

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#extends","title":"Extends","text":"
      • Iterable<[string, string[]]>
      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#code","title":"code","text":"

      code: number

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#description","title":"description","text":"

      description: string

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#haserror","title":"hasError","text":"

      hasError: boolean

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#status","title":"status","text":"

      status: string

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#iterator","title":"[iterator]()","text":"

      [iterator](): Iterator<[string, string[]], any, undefined>

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns","title":"Returns","text":"

      Iterator<[string, string[]], any, undefined>

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#inherited-from","title":"Inherited from","text":"

      Iterable.[iterator]

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#append","title":"append()","text":"

      append(k, v, match?): void

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters","title":"Parameters","text":"

      \u2022 k: string

      \u2022 v: string

      \u2022 match?: Match

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_1","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#delete","title":"delete()","text":"

      delete(k, match?): void

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_1","title":"Parameters","text":"

      \u2022 k: string

      \u2022 match?: Match

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_2","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#get","title":"get()","text":"

      get(k, match?): string

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_2","title":"Parameters","text":"

      \u2022 k: string

      \u2022 match?: Match

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_3","title":"Returns","text":"

      string

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#has","title":"has()","text":"

      has(k, match?): boolean

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_3","title":"Parameters","text":"

      \u2022 k: string

      \u2022 match?: Match

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_4","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#keys","title":"keys()","text":"

      keys(): string[]

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_5","title":"Returns","text":"

      string[]

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#last","title":"last()","text":"

      last(k, match?): string

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_4","title":"Parameters","text":"

      \u2022 k: string

      \u2022 match?: Match

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_6","title":"Returns","text":"

      string

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#set","title":"set()","text":"

      set(k, v, match?): void

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_5","title":"Parameters","text":"

      \u2022 k: string

      \u2022 v: string

      \u2022 match?: Match

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_7","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#values","title":"values()","text":"

      values(k, match?): string[]

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_6","title":"Parameters","text":"

      \u2022 k: string

      \u2022 match?: Match

      "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_8","title":"Returns","text":"

      string[]

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/","title":"NatsConnection","text":"

      @wuespace/telestion / nats / NatsConnection

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#info","title":"info?","text":"

      info?: ServerInfo

      ServerInfo to the currently connected server or undefined

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#services","title":"services","text":"

      services: ServicesAPI

      Returns a ServicesAPI which allows you to build services using NATS.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#close","title":"close()","text":"

      close(): Promise<void>

      Close will close the connection to the server. This call will terminate all pending requests and subscriptions. The returned promise resolves when the connection closes.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns","title":"Returns","text":"

      Promise<void>

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#closed","title":"closed()","text":"

      closed(): Promise<void | Error>

      Returns a promise that can be used to monitor if the client closes. The promise can resolve an Error if the reason for the close was an error. Note that the promise doesn\u2019t reject, but rather resolves to the error if there was one.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_1","title":"Returns","text":"

      Promise<void | Error>

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#drain","title":"drain()","text":"

      drain(): Promise<void>

      Initiates a drain on the connection and returns a promise that resolves when the drain completes and the connection closes.

      Drain is an ordered shutdown of the client. Instead of abruptly closing the client, subscriptions are drained, that is messages not yet processed by a subscription are handled before the subscription is closed. After subscriptions are drained it is not possible to create a new subscription. Then all pending outbound messages are sent to the server. Finally, the connection is closed.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_2","title":"Returns","text":"

      Promise<void>

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#flush","title":"flush()","text":"

      flush(): Promise<void>

      Returns a Promise that resolves when the client receives a reply from the server. Use of this API is not necessary by clients.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_3","title":"Returns","text":"

      Promise<void>

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#getserver","title":"getServer()","text":"

      getServer(): string

      Returns the hostport of the server the client is connected to.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_4","title":"Returns","text":"

      string

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#isclosed","title":"isClosed()","text":"

      isClosed(): boolean

      Returns true if the client is closed.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_5","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#isdraining","title":"isDraining()","text":"

      isDraining(): boolean

      Returns true if the client is draining.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_6","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#jetstream","title":"jetstream()","text":"

      jetstream(opts?): JetStreamClient

      Returns a JetStreamClient which allows publishing messages to JetStream or consuming messages from streams.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters","title":"Parameters","text":"

      \u2022 opts?: JetStreamOptions

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_7","title":"Returns","text":"

      JetStreamClient

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#jetstreammanager","title":"jetstreamManager()","text":"

      jetstreamManager(opts?): Promise<JetStreamManager>

      Returns a Promise to a JetStreamManager which allows the client to access Streams and Consumers information.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters_1","title":"Parameters","text":"

      \u2022 opts?: JetStreamManagerOptions

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_8","title":"Returns","text":"

      Promise<JetStreamManager>

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#publish","title":"publish()","text":"

      publish(subject, payload?, options?): void

      Publishes the specified data to the specified subject.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters_2","title":"Parameters","text":"

      \u2022 subject: string

      \u2022 payload?: Payload

      \u2022 options?: PublishOptions

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_9","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#reconnect","title":"reconnect()","text":"

      reconnect(): Promise<void>

      Use of this API is experimental, and it is subject to be removed.

      reconnect() enables a client to force a reconnect. A reconnect will disconnect the client, and possibly initiate a reconnect to the cluster. Note that all reconnect caveats apply:

      • If the reconnection policy given to the client doesn\u2019t allow reconnects, the connection will close.

      • Messages that are inbound or outbound could be lost.

      • All requests that are in flight will be rejected.

      Note that the returned promise will reject if the client is already closed, or if it is in the process of draining. If the client is currently disconnected, this API has no effect, as the client is already attempting to reconnect.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_10","title":"Returns","text":"

      Promise<void>

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#request","title":"request()","text":"

      request(subject, payload?, opts?): Promise<Msg>

      Publishes a request with specified data in the specified subject expecting a response before RequestOptions#timeout milliseconds. The api returns a Promise that resolves when the first response to the request is received. If there are no responders (a subscription) listening on the request subject, the request will fail as soon as the server processes it.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters_3","title":"Parameters","text":"

      \u2022 subject: string

      \u2022 payload?: Payload

      \u2022 opts?: RequestOptions

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_11","title":"Returns","text":"

      Promise<Msg>

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#requestmany","title":"requestMany()","text":"

      requestMany(subject, payload?, opts?): Promise<AsyncIterable<Msg>>

      Publishes a request expecting multiple responses back. Several strategies to determine when the request should stop gathering responses.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters_4","title":"Parameters","text":"

      \u2022 subject: string

      \u2022 payload?: Payload

      \u2022 opts?: Partial<RequestManyOptions>

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_12","title":"Returns","text":"

      Promise<AsyncIterable<Msg>>

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#rtt","title":"rtt()","text":"

      rtt(): Promise<number>

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_13","title":"Returns","text":"

      Promise<number>

      the number of milliseconds it took for a flush.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#stats","title":"stats()","text":"

      stats(): Stats

      Returns some metrics such as the number of messages and bytes sent and recieved by the client.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_14","title":"Returns","text":"

      Stats

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#status","title":"status()","text":"

      status(): AsyncIterable<Status>

      Returns an async iterator of Status that may be useful in understanding when the client looses a connection, or reconnects, or receives an update from the cluster among other things.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_15","title":"Returns","text":"

      AsyncIterable<Status>

      an AsyncIterable"},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#subscribe","title":"subscribe()","text":"

      subscribe(subject, opts?): Subscription

      Subscribe expresses interest in the specified subject. The subject may have wildcards. Messages are delivered to the SubscriptionOptions callback if specified. Otherwise, the subscription is an async iterator for Msg.

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters_5","title":"Parameters","text":"

      \u2022 subject: string

      \u2022 opts?: SubscriptionOptions

      "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_16","title":"Returns","text":"

      Subscription

      "},{"location":"Frontend%20Development/api/nats/interfaces/PublishOptions/","title":"PublishOptions","text":"

      @wuespace/telestion / nats / PublishOptions

      "},{"location":"Frontend%20Development/api/nats/interfaces/PublishOptions/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/PublishOptions/#headers","title":"headers?","text":"

      headers?: MsgHdrs

      Optional headers to include with the message.

      "},{"location":"Frontend%20Development/api/nats/interfaces/PublishOptions/#reply","title":"reply?","text":"

      reply?: string

      An optional subject where a response should be sent. Note you must have a subscription listening on this subject to receive the response.

      "},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/","title":"RequestOptions","text":"

      @wuespace/telestion / nats / RequestOptions

      "},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/#headers","title":"headers?","text":"

      headers?: MsgHdrs

      MsgHdrs to include with the request.

      "},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/#nomux","title":"noMux?","text":"

      noMux?: boolean

      If true, the request API will create a regular NATS subscription to process the response. Otherwise a shared muxed subscriptions is used. Requires reply

      "},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/#reply","title":"reply?","text":"

      reply?: string

      The subject where the response should be sent to. Requires noMux

      "},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/#timeout","title":"timeout","text":"

      timeout: number

      number of milliseconds before the request will timeout.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/","title":"Sub","text":"

      @wuespace/telestion / nats / Sub

      Basic interface to a Subscription type

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#extends","title":"Extends","text":"
      • AsyncIterable<T>
      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#type-parameters","title":"Type parameters","text":"

      \u2022 T

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#closed","title":"closed","text":"

      closed: Promise<void>

      A promise that resolves when the subscription closes

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#asynciterator","title":"[asyncIterator]()","text":"

      [asyncIterator](): AsyncIterator<T, any, undefined>

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns","title":"Returns","text":"

      AsyncIterator<T, any, undefined>

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#inherited-from","title":"Inherited from","text":"

      AsyncIterable.[asyncIterator]

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#drain","title":"drain()","text":"

      drain(): Promise<void>

      Drain the subscription, closing it after processing all messages currently in flight for the client. Returns a promise that resolves when the subscription finished draining.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_1","title":"Returns","text":"

      Promise<void>

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#getmax","title":"getMax()","text":"

      getMax(): undefined | number

      Return the max number of messages before the subscription will unsubscribe.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_2","title":"Returns","text":"

      undefined | number

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#getpending","title":"getPending()","text":"

      getPending(): number

      Returns the number of messages that are pending processing. Note that this is method is only valid for iterators.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_3","title":"Returns","text":"

      number

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#getprocessed","title":"getProcessed()","text":"

      getProcessed(): number

      Returns the number of messages that have been processed by the subscription.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_4","title":"Returns","text":"

      number

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#getreceived","title":"getReceived()","text":"

      getReceived(): number

      Returns the number of messages received by the subscription.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_5","title":"Returns","text":"

      number

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#getsubject","title":"getSubject()","text":"

      getSubject(): string

      Returns the subject that was used to create the subscription.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_6","title":"Returns","text":"

      string

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#isclosed","title":"isClosed()","text":"

      isClosed(): boolean

      Returns true if the subscription is closed.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_7","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#isdraining","title":"isDraining()","text":"

      isDraining(): boolean

      Returns true if the subscription is draining.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_8","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#unsubscribe","title":"unsubscribe()","text":"

      unsubscribe(max?): void

      Stop the subscription from receiving messages. You can optionally specify that the subscription should stop after the specified number of messages have been received. Note this count is since the lifetime of the subscription.

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#parameters","title":"Parameters","text":"

      \u2022 max?: number

      "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_9","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/","title":"SubOpts","text":"

      @wuespace/telestion / nats / SubOpts

      Subscription Options

      "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#type-parameters","title":"Type parameters","text":"

      \u2022 T

      "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#callback","title":"callback?","text":"

      callback?: (err, msg) => void

      An optional function that will handle messages. Typically, messages are processed via an async iterator on the subscription. If this option is provided, messages are processed by the specified function.

      "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#parameters","title":"Parameters","text":"

      \u2022 err: null | NatsError

      \u2022 msg: T

      "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#returns","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#max","title":"max?","text":"

      max?: number

      Optional maximum number of messages to deliver to the subscription before it is auto-unsubscribed.

      "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#queue","title":"queue?","text":"

      queue?: string

      Optional queue name (subscriptions on the same subject that use queues are horizontally load balanced when part of the same queue).

      "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#timeout","title":"timeout?","text":"

      timeout?: number

      Optional maximum number of milliseconds before a timer raises an error. This useful to monitor a subscription that is expected to yield messages. The timer is cancelled when the first message is received by the subscription.

      "},{"location":"Frontend%20Development/api/nats/type-aliases/MsgRequest/","title":"MsgRequest","text":"

      @wuespace/telestion / nats / MsgRequest

      MsgRequest: SeqMsgRequest | LastForMsgRequest | number

      "},{"location":"Frontend%20Development/api/nats/type-aliases/Subscription/","title":"Subscription","text":"

      @wuespace/telestion / nats / Subscription

      Subscription: Sub<Msg>

      Type alias for NATS core subscriptions

      "},{"location":"Frontend%20Development/api/nats/type-aliases/SubscriptionOptions/","title":"SubscriptionOptions","text":"

      @wuespace/telestion / nats / SubscriptionOptions

      SubscriptionOptions: SubOpts<Msg>

      Subscription Options

      "},{"location":"Frontend%20Development/api/user-data/","title":"Index","text":"

      @wuespace/telestion / user-data

      Types and utilities for interacting with the user data stored on the user\u2019s device.

      "},{"location":"Frontend%20Development/api/user-data/#example","title":"Example","text":"
      import { ... } from '@wuespace/telestion/user-data';\n
      "},{"location":"Frontend%20Development/api/user-data/#type-aliases","title":"Type Aliases","text":"
      • Dashboard
      • WidgetInstance
      "},{"location":"Frontend%20Development/api/user-data/#variables","title":"Variables","text":"
      • dashboardSchema
      • idSchema
      • layoutSchema
      • semverRegExp
      • userDataSchema
      • widgetInstanceSchema
      "},{"location":"Frontend%20Development/api/user-data/#functions","title":"Functions","text":"
      • getBlankUserData
      • getEmptyDashboard
      • getUserData
      • removeUserData
      • setUserData
      "},{"location":"Frontend%20Development/api/user-data/#references","title":"References","text":""},{"location":"Frontend%20Development/api/user-data/#userdata","title":"UserData","text":"

      Re-exports UserData

      "},{"location":"Frontend%20Development/api/user-data/functions/getBlankUserData/","title":"getBlankUserData","text":"

      @wuespace/telestion / user-data / getBlankUserData

      getBlankUserData(version): UserData

      Returns a new blank user data object.

      "},{"location":"Frontend%20Development/api/user-data/functions/getBlankUserData/#parameters","title":"Parameters","text":"

      \u2022 version: string

      the current application version

      "},{"location":"Frontend%20Development/api/user-data/functions/getBlankUserData/#returns","title":"Returns","text":"

      UserData

      "},{"location":"Frontend%20Development/api/user-data/functions/getEmptyDashboard/","title":"getEmptyDashboard","text":"

      @wuespace/telestion / user-data / getEmptyDashboard

      getEmptyDashboard(): readonly [string, Dashboard]

      Returns a new and empty dashboard with a unique id.

      "},{"location":"Frontend%20Development/api/user-data/functions/getEmptyDashboard/#returns","title":"Returns","text":"

      readonly [string, Dashboard]

      "},{"location":"Frontend%20Development/api/user-data/functions/getUserData/","title":"getUserData","text":"

      @wuespace/telestion / user-data / getUserData

      getUserData(): undefined | Object

      Retrieves user data from local storage.

      "},{"location":"Frontend%20Development/api/user-data/functions/getUserData/#returns","title":"Returns","text":"

      undefined | Object

      The user data if found in local storage, otherwise undefined.

      "},{"location":"Frontend%20Development/api/user-data/functions/removeUserData/","title":"removeUserData","text":"

      @wuespace/telestion / user-data / removeUserData

      removeUserData(): void

      Removes the user data from local storage.

      "},{"location":"Frontend%20Development/api/user-data/functions/removeUserData/#returns","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/user-data/functions/setUserData/","title":"setUserData","text":"

      @wuespace/telestion / user-data / setUserData

      setUserData(newUserData): void

      Sets the user data in the local storage based on the given input.

      "},{"location":"Frontend%20Development/api/user-data/functions/setUserData/#parameters","title":"Parameters","text":"

      \u2022 newUserData: Object

      The new user data to be set.

      \u2022 newUserData.dashboards: Record<string, { title: string; layout: string[][]; }>= undefined

      The user\u2019s dashboards.

      \u2022 newUserData.version: string= undefined

      The version of the client that created this user data.

      \u2022 newUserData.widgetInstances: Record<string, { type: string; configuration: Record<string, unknown>; }>= undefined

      The user\u2019s widget instances.

      "},{"location":"Frontend%20Development/api/user-data/functions/setUserData/#returns","title":"Returns","text":"

      void

      "},{"location":"Frontend%20Development/api/user-data/type-aliases/Dashboard/","title":"Dashboard","text":"

      @wuespace/telestion / user-data / Dashboard

      Dashboard: Object

      Represents a dashboard.

      "},{"location":"Frontend%20Development/api/user-data/type-aliases/Dashboard/#see","title":"See","text":"

      dashboardSchema

      "},{"location":"Frontend%20Development/api/user-data/type-aliases/Dashboard/#type-declaration","title":"Type declaration","text":""},{"location":"Frontend%20Development/api/user-data/type-aliases/Dashboard/#layout","title":"layout","text":"

      layout: string[][] = layoutSchema

      The layout of the dashboard.

      "},{"location":"Frontend%20Development/api/user-data/type-aliases/Dashboard/#title","title":"title","text":"

      title: string

      The title of the dashboard.

      "},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/","title":"WidgetInstance","text":"

      @wuespace/telestion / user-data / WidgetInstance

      WidgetInstance: Object

      Represents a widget instance.

      "},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/#see","title":"See","text":"

      widgetInstanceSchema

      "},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/#type-declaration","title":"Type declaration","text":""},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/#configuration","title":"configuration","text":"

      configuration: Record<string, unknown>

      The configuration of the widget.

      "},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/#type","title":"type","text":"

      type: string

      The type ID of the widget.

      This is used to determine which widget type to use to render the widget.

      "},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/#see_1","title":"See","text":"

      Widget.id

      "},{"location":"Frontend%20Development/api/user-data/variables/dashboardSchema/","title":"dashboardSchema","text":"

      @wuespace/telestion / user-data / dashboardSchema

      const dashboardSchema: ZodObject<Dashboard>

      Represents the schema for a dashboard.

      "},{"location":"Frontend%20Development/api/user-data/variables/idSchema/","title":"idSchema","text":"

      @wuespace/telestion / user-data / idSchema

      const idSchema: ZodString

      A regular expression that matches valid identifiers.

      Used for dashboard and widget instance IDs.

      "},{"location":"Frontend%20Development/api/user-data/variables/idSchema/#see","title":"See","text":"

      WidgetInstance

      "},{"location":"Frontend%20Development/api/user-data/variables/layoutSchema/","title":"layoutSchema","text":"

      @wuespace/telestion / user-data / layoutSchema

      const layoutSchema: ZodArray<ZodArray<ZodUnion<[ZodString, ZodLiteral<\".\">]>, \"many\">, \"many\">

      A schema that matches valid layout configurations.

      "},{"location":"Frontend%20Development/api/user-data/variables/semverRegExp/","title":"semverRegExp","text":"

      @wuespace/telestion / user-data / semverRegExp

      const semverRegExp: RegExp

      A regular expression that matches semantic version numbers.

      Taken from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string

      "},{"location":"Frontend%20Development/api/user-data/variables/userDataSchema/","title":"userDataSchema","text":"

      @wuespace/telestion / user-data / userDataSchema

      const userDataSchema: ZodObject<UserData>

      The schema for the user data.

      "},{"location":"Frontend%20Development/api/user-data/variables/userDataSchema/#see","title":"See","text":"

      UserData

      "},{"location":"Frontend%20Development/api/user-data/variables/widgetInstanceSchema/","title":"widgetInstanceSchema","text":"

      @wuespace/telestion / user-data / widgetInstanceSchema

      const widgetInstanceSchema: ZodObject<WidgetInstance>

      Represents the schema for a widget instance.

      "},{"location":"Frontend%20Development/api/user-data/variables/widgetInstanceSchema/#see","title":"See","text":"

      WidgetInstance

      "},{"location":"Frontend%20Development/api/utils/","title":"Index","text":"

      @wuespace/telestion / utils

      Various utility functions around building Telestion frontend apps.

      "},{"location":"Frontend%20Development/api/utils/#example","title":"Example","text":"
      import { ... } from '@wuespace/telestion/utils';\n
      "},{"location":"Frontend%20Development/api/utils/#index","title":"Index","text":""},{"location":"Frontend%20Development/api/utils/#functions","title":"Functions","text":"
      • generateDashboardId
      • isUserDataUpToDate
      • loadFileContents
      • wait
      "},{"location":"Frontend%20Development/api/utils/functions/generateDashboardId/","title":"generateDashboardId","text":"

      @wuespace/telestion / utils / generateDashboardId

      generateDashboardId(): string

      Generates a unique identifier for a dashboard.

      "},{"location":"Frontend%20Development/api/utils/functions/generateDashboardId/#returns","title":"Returns","text":"

      string

      The generated dashboard identifier.

      "},{"location":"Frontend%20Development/api/utils/functions/isUserDataUpToDate/","title":"isUserDataUpToDate","text":"

      @wuespace/telestion / utils / isUserDataUpToDate

      isUserDataUpToDate(userData, currentVersion): boolean

      Checks if the user data is up-to-date with the current version of the application.

      "},{"location":"Frontend%20Development/api/utils/functions/isUserDataUpToDate/#parameters","title":"Parameters","text":"

      \u2022 userData: undefined | Object

      the user data to compare with the application version

      \u2022 currentVersion: string

      the current version of the application

      "},{"location":"Frontend%20Development/api/utils/functions/isUserDataUpToDate/#returns","title":"Returns","text":"

      boolean

      "},{"location":"Frontend%20Development/api/utils/functions/loadFileContents/","title":"loadFileContents","text":"

      @wuespace/telestion / utils / loadFileContents

      loadFileContents(file, encoding): Promise<string>

      Loads the contents of a specified file.

      "},{"location":"Frontend%20Development/api/utils/functions/loadFileContents/#parameters","title":"Parameters","text":"

      \u2022 file: File

      The file object to load contents from.

      \u2022 encoding: string= 'utf-8'

      The encoding to use while reading the file. Default is UTF-8.

      "},{"location":"Frontend%20Development/api/utils/functions/loadFileContents/#returns","title":"Returns","text":"

      Promise<string>

      • A Promise that resolves with the contents of the file as a string. - If the file is empty, the Promise will be rejected with an error.
      "},{"location":"Frontend%20Development/api/utils/functions/wait/","title":"Wait","text":"

      @wuespace/telestion / utils / wait

      wait(timeout): Promise<void>

      Waits for the specified amount of time before resolving the returned promise.

      "},{"location":"Frontend%20Development/api/utils/functions/wait/#parameters","title":"Parameters","text":"

      \u2022 timeout: number

      The duration in milliseconds to wait before resolving.

      "},{"location":"Frontend%20Development/api/utils/functions/wait/#returns","title":"Returns","text":"

      Promise<void>

      A promise that resolves after the specified time has elapsed.

      "},{"location":"Frontend%20Development/api/widget/","title":"Index","text":"

      @wuespace/telestion / widget

      Everything you need for building and/or displaying widgets.

      "},{"location":"Frontend%20Development/api/widget/#example","title":"Example","text":"
      import { ... } from '@wuespace/telestion/widget';\n
      "},{"location":"Frontend%20Development/api/widget/#interfaces","title":"Interfaces","text":"
      • WidgetRendererProps
      "},{"location":"Frontend%20Development/api/widget/#variables","title":"Variables","text":"
      • widgetConfigContext
      "},{"location":"Frontend%20Development/api/widget/#functions","title":"Functions","text":"
      • WidgetRenderer
      • getWidgetById
      • getWidgets
      "},{"location":"Frontend%20Development/api/widget/#references","title":"References","text":""},{"location":"Frontend%20Development/api/widget/#widget","title":"Widget","text":"

      Re-exports Widget

      "},{"location":"Frontend%20Development/api/widget/#registerwidgets","title":"registerWidgets","text":"

      Re-exports registerWidgets

      "},{"location":"Frontend%20Development/api/widget/functions/WidgetRenderer/","title":"WidgetRenderer","text":"

      @wuespace/telestion / widget / WidgetRenderer

      WidgetRenderer(WidgetRendererProps): Element

      Renders a widget based on the provided widgetInstanceId.

      "},{"location":"Frontend%20Development/api/widget/functions/WidgetRenderer/#parameters","title":"Parameters","text":"

      \u2022 WidgetRendererProps: WidgetRendererProps

      The props for the WidgetRenderer.

      "},{"location":"Frontend%20Development/api/widget/functions/WidgetRenderer/#returns","title":"Returns","text":"

      Element

      The rendered widget.

      "},{"location":"Frontend%20Development/api/widget/functions/WidgetRenderer/#throws","title":"Throws","text":"

      Error If the widget instance is not found.

      "},{"location":"Frontend%20Development/api/widget/functions/getWidgetById/","title":"getWidgetById","text":"

      @wuespace/telestion / widget / getWidgetById

      getWidgetById(id): undefined | Widget<Record<string, unknown>>

      Retrieves a widget by its unique type ID.

      "},{"location":"Frontend%20Development/api/widget/functions/getWidgetById/#parameters","title":"Parameters","text":"

      \u2022 id: string

      The unique type ID of the widget.

      "},{"location":"Frontend%20Development/api/widget/functions/getWidgetById/#returns","title":"Returns","text":"

      undefined | Widget<Record<string, unknown>>

      The widget associated with the ID, or null if the widget is not found.

      "},{"location":"Frontend%20Development/api/widget/functions/getWidgets/","title":"getWidgets","text":"

      @wuespace/telestion / widget / getWidgets

      getWidgets(): Widget<Record<string, unknown>>[]

      Returns an array of all the widgets that are currently registered.

      "},{"location":"Frontend%20Development/api/widget/functions/getWidgets/#returns","title":"Returns","text":"

      Widget<Record<string, unknown>>[]

      An array containing all the widgets.

      "},{"location":"Frontend%20Development/api/widget/interfaces/WidgetRendererProps/","title":"WidgetRendererProps","text":"

      @wuespace/telestion / widget / WidgetRendererProps

      "},{"location":"Frontend%20Development/api/widget/interfaces/WidgetRendererProps/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/widget/interfaces/WidgetRendererProps/#widgetinstanceid","title":"widgetInstanceId","text":"

      widgetInstanceId: string

      "},{"location":"Frontend%20Development/api/widget/variables/widgetConfigContext/","title":"widgetConfigContext","text":"

      @wuespace/telestion / widget / widgetConfigContext

      const widgetConfigContext: Context<unknown>

      "},{"location":"_writers-guide/","title":"Writer\u2019s Guide","text":""},{"location":"_writers-guide/#introduction","title":"Introduction","text":"

      This guide is intended to help you write documentation.

      "},{"location":"_writers-guide/#writing-style","title":"Writing Style","text":""},{"location":"_writers-guide/#general","title":"General","text":"
      • Use the active voice.
      • Use the present tense.
      • Use the second person.
      • Use the imperative mood.
      • Use they/them/their as singular pronouns.
      "},{"location":"_writers-guide/#markdown","title":"Markdown","text":""},{"location":"_writers-guide/#general_1","title":"General","text":"
      • Use the GitHub Flavored Markdown syntax.
      • Use the CommonMark specification.
      "},{"location":"_writers-guide/#headings","title":"Headings","text":"
      • Use # for headings.
      • Use ## for subheadings.
      • Use ### for sub-subheadings.
      "},{"location":"_writers-guide/#lists","title":"Lists","text":"
      • Use * for unordered lists.
      • Use 1. for ordered lists.
      • Use * for nested unordered lists.
      • Use 1. for nested ordered lists.
      "},{"location":"_writers-guide/#links","title":"Links","text":"
      • Use [text](url) for links.
      "},{"location":"_writers-guide/#internal-links","title":"Internal Links","text":"
      • Use relative links for internal links.
      • Use the .md extension for internal links.
      • Use the # symbol for internal links to (sub-) headings.

      Example

      [Telestion Website](https://telestion.wuespace.de)\n\n[Deployment Pre-requisites](Deployment/prerequesites.md)\n\n[Deployment Pre-requisites](Deployment/prerequesites.md#deployment-pre-requisites)\n
      "},{"location":"_writers-guide/#images","title":"Images","text":"
      • Use ![alt text](url) for images.
      • Write the alt text in sentence case.
      • Place images close to the text that references them.
      • Use the PNG format for images.
      • Use the SVG format for logos and icons.
      • Use the JPEG format for photographs.
      • Use the GIF format for animations.

      For images that can be inverted for the dark theme, use the following syntax:

      ![alt text](url){ .invertible }\n

      To add a caption to an image, use the following syntax:

      <figure markdown>\n![alt text](url)\n<figcaption>Image caption</figcaption>\n</figure>\n

      Example

      ![alt text](url)\n\n![alt text](url){ .invertible }\n\n<figure markdown>\n![alt text](url)\n<figcaption>Image caption</figcaption>\n</figure>\n
      "},{"location":"_writers-guide/#code-blocks","title":"Code Blocks","text":"
      • Use ``` for code blocks.
      • Use ```language for code blocks with syntax highlighting.
      • Use ```language title=\"name\" for code blocks with syntax highlighting and a title.

      Example

      ```java\npublic static void main(String[] args) {\n    System.out.println(\"Hello World!\");\n}\n```\n\n```java title=\"Hello World\"\npublic static void main(String[] args) {\n    System.out.println(\"Hello World!\");\n}\n```\n
      "},{"location":"_writers-guide/#admonitions","title":"Admonitions","text":"
      • Use !!! note for notes.
      • Use !!! tip for tips.
      • Use !!! warning for warnings.
      • Use !!! danger for dangers.
      • Use !!! example for examples.
      • Use !!! question for questions.

      Example

      !!! note\n    This is a note.\n\n!!! tip\n    This is a tip.\n\n!!! warning\n    This is a warning.\n\n!!! danger\n    This is a danger.\n\n!!! example\n    This is an example.\n\n!!! question\n    This is a question.\n
      "},{"location":"_writers-guide/#keyboard-shortcuts","title":"Keyboard Shortcuts","text":"
      • Use ++ for keyboard shortcuts.
      • Use ++ctrl+f++ for keyboard shortcuts with multiple keys.
      • Use lowercase letters for keyboard shortcuts.

      Example

      Press Ctrl+F to open the menu.

      Press ++ctrl+f++ to open the menu.\n
      "}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Telestion Developer Documentation","text":"

      Telestion is a framework for building telemetry applications. You can find more information about the project on the project website.

      This documentation is about developing a Ground Station software using Telestion. For end-user documentation, please ask your Telestion developer.

      Get started

      "},{"location":"#quick-links","title":"Quick links","text":""},{"location":"#github-repositories","title":"GitHub repositories","text":"
      • Telestion \u2013 The main repository for the Telestion project
      • Telestion Architecture \u2013 The repository that hosts the ADRs (Architecture Decision Records) for the Telestion project
      "},{"location":"#related-projects","title":"Related projects","text":"
      • NATS \u2013 The message bus used by Telestion
      • TypeScript \u2013 The programming language used for most components by Telestion
      • Deno \u2013 The runtime used by Telestion for TypeScript and JavaScript based services
      • React \u2013 The frontend framework used by Telestion
      "},{"location":"#discord","title":"Discord","text":"

      The Telestion Discord server is the best place to interact with the Telestion community. You can ask questions, get help, and discuss the project with other users and developers.

      Join the Discord server

      "},{"location":"getting-started/","title":"Getting started","text":"

      (coming soon)

      "},{"location":"message-bus/","title":"Message Bus","text":"

      The message bus is a simple, lightweight, and fast way to send messages between different parts (services) of your application. It\u2019s a publish/subscribe system that allows you to send messages to a specific subject and have any listeners on that subject receive the message.

      "},{"location":"message-bus/#messages","title":"Messages","text":"

      Messages are the way that data is sent between services. In the Telestion ecosystem. Messages are either JSON or binary data.

      "},{"location":"message-bus/#subjects","title":"Subjects","text":"

      Subjects are the way that messages are sent between services. Each subject has a name. The name is used to identify the subject.

      "},{"location":"message-bus/#publish-subscribe","title":"Publish / Subscribe","text":"

      The message bus is a publish/subscribe system. This means that you can publish messages to a specific subject and have any listeners on that subject receive the message.

      Warning

      Messages aren\u2019t stored when using the publish/subscribe method. This means that if a service isn\u2019t listening on a subject when a message gets published, it won\u2019t receive the message.

      If you need to ensure that a message is received, you can use the Request / Reply system to await confirmation.

      "},{"location":"message-bus/#example","title":"Example","text":"

      Here is an example of how the publish/subscribe system works:

      sequenceDiagram\n    accTitle: Sequence diagram of the publish/subscribe system. Text description in collapsed section below.\n    participant Service A\n    participant Message Bus\n    participant Service B\n    Service A->>Message Bus: Subscribe to subject \"test\"\n    Service B->>Message Bus: Publish message \"Hello World\" to subject \"test\"\n    Message Bus->>Service A: Message \"Hello World\" on subject \"test\"
      Text Description
      1. Service A subscribes to the subject \u201ctest\u201d on the message bus
      2. Service B publishes the message \u201cHello World\u201d to the subject \u201ctest\u201d
      3. The message bus sends the message \u201cHello World\u201d to Service A
      "},{"location":"message-bus/#request-reply","title":"Request / Reply","text":"

      The message bus is also a request/reply system. This means that you can send a request to a specific subject and have any listeners on that subject reply to the request.

      "},{"location":"message-bus/#example_1","title":"Example","text":"

      Here is an example of how the request/reply system works:

      sequenceDiagram\n    accTitle: Sequence diagram of the request/reply system. Text description in collapsed section below.\n    participant Service A\n    participant Message Bus\n    participant Service B\n    Service B->>Message Bus: Subscribe to subject \"test\"\n    Service A->>Message Bus: Send request \"Hello World\" to subject \"test\"\n    Message Bus->>Service B: Request \"Hello World\" on subject \"test\"\n    Service B->>Message Bus: Reply \"Hello World\" to subject \"test\"\n    Message Bus->>Service A: Reply \"Hello World\" on subject \"test\"
      Text Description
      1. Service B subscribes to the subject \u201ctest\u201d on the message bus
      2. Service A sends the request \u201cHello World\u201d to the subject \u201ctest\u201d
      3. The message bus sends the request \u201cHello World\u201d to Service B
      4. Service B replies to the request with \u201cHello World\u201d
      5. The message bus sends the reply \u201cHello World\u201d to Service A
      "},{"location":"message-bus/#nats","title":"NATS","text":"

      We use NATS as our message bus. While all other services can be replaced, the message bus is a core component of Telestion. It is the backbone of the entire system.

      "},{"location":"message-bus/#authentication-and-authorization","title":"Authentication and Authorization","text":"

      NATS also handles everything related to authentication and authorization for the message bus. You can easily control who can send and receive messages on which subjects.

      "},{"location":"project-folder-structure/","title":"Project folder structure","text":"

      Every Telestion project is different, and so is its folder structure. Some projects might not even have a frontend and write every backend service in Java, while others might have a frontend and use Deno for their backend services.

      That\u2019s not very helpful, is it? So, let\u2019s take a look at a folder structure that is suitable for most projects. Note that as your project grows, you might want to change the structure to better suit your needs. But you will know when the time has come.

      "},{"location":"project-folder-structure/#version-control","title":"Version control","text":"

      The first thing you should do is to create a new Git repository. This repository will contain all the code for your project. You can use GitHub, GitLab, or any other Git hosting service you like.

      "},{"location":"project-folder-structure/#recommended-folder-structure","title":"Recommended folder structure","text":"

      The following folder structure is recommended for most projects:

      • backend-deno - A folder that contains all backend services written in Deno.
        • [service-name] - A folder that contains a backend service written in Deno.
          • mod.ts - The entry point of the backend service.
          • README.md - A file that contains information about the backend service.
        • Dockerfile - A Dockerfile for the Deno-based backend services, if you want to use Docker.
      • frontend-react - A folder that contains the frontend written in React.
        • package.json - The frontend application\u2019s package.json file.
        • \u2026
      • frontend-cli - A folder that contains the CLI frontend written in Deno.
        • mod.ts - The entry point of the CLI.
        • README.md - A file that contains information about the CLI.
      • nats - A folder that contains the NATS server configuration.
        • nats-server.conf - The configuration file for the NATS server.
      • docker-compose.yml - A Docker Compose file that contains the configuration for the Docker containers.
      • README.md - A file that contains information about the project.
      "},{"location":"project-folder-structure/#alternatives","title":"Alternatives","text":"

      There are also other options how you could structure your project. For example, if you have completely distinct groups of services that are not related to each other, you could create a folder for each group, and differentiate between programming languages used under these groups.

      However, to get started, the above structure should be sufficient. You can always change it later.

      "},{"location":"service/","title":"Services","text":"

      Services are small, self-contained, and (ideally) stateless applications that can be deployed and scaled independently. They\u2019re designed to be used in conjunction with other services and are often packaged together to form a larger application.

      In less abstract terms, a service is a single application that is part of the bigger Telestion application. It is a single application that is responsible for a single task. For example, the project template contains the following services by default:

      • Frontend: A web application that is responsible for displaying the user interface
      • Database Service: A service that is responsible for storing data
      • Database Query Service: A service that is responsible for querying the database
      • Data Splitter Service: A service that is responsible for creating mock data to test the application
      "},{"location":"service/#service-types","title":"Service Types","text":"

      There are two types of services:

      • Frontend Services: Services that are responsible for displaying the user interface
      • Backend Services: Services that are responsible for processing data

      Info

      Concretely, the main difference between frontend and backend is that frontend services act on behalf of the user, while backend services act on behalf of the system.

      "},{"location":"service/#service-architecture","title":"Service Architecture","text":"

      While similar to the common microservice architecture, Telestion is less strict about its services. For example, Telestion services are not required to be stateless. While state in services makes it harder to scale them, it also makes it easier to develop them.

      Telestion services are also not required to be deployed independently. They can be deployed together as a single application.

      "},{"location":"service/#service-communication","title":"Service Communication","text":"

      Telestion services communicate via the NATS message bus. This means that they can send messages to each other and receive messages from each other. This allows them to communicate with each other without having to know each other\u2019s IP addresses or ports.

      "},{"location":"Backend%20Development/","title":"Developing Backend Services","text":"

      Backend services are small, self-contained, and (ideally) stateless applications that can be deployed and scaled independently. They are designed to be used in conjunction with other services and are often packaged together to form a larger application.

      ","tags":["Backend"]},{"location":"Backend%20Development/#example-structure","title":"Example Structure","text":"

      The following is an example for the combination of services creating the backend of a Telestion application:

      graph TB\n    accTitle: Diagram showcasing the structure of an exemplary Telestion backend. Text description in collapsible section below.\n    db[Database]\n    md[Mission Device]\n    subgraph Backend\n        io[IO Service]\n        tmps[Telemetry Parser Service]\n        tcs[Telecommand Service]\n        dbs[Database Writer Service]\n        dbqs[Database Query Service]\n    end\n    subgraph Frontend\n        wc[Web Client]\n    end\n    md <---> io\n    io --> tmps\n    tmps --> dbs\n    dbs --> db\n    wc --> dbqs\n    dbqs --> db\n    wc --> tcs\n    tcs --> io
      Text Description
      1. The Mission Device sends telemetry data to the IO Service.
      2. The IO Service (backend) forwards the telemetry data to the Telemetry Parser Service.
      3. The Telemetry Parser Service (backend) parses the telemetry data and writes it to the database via the Database Writer Service.
      4. The Database Writer Service (backend) writes the telemetry data to the database.
      5. The Web Client (frontend) queries the database via the Database Query Service.
      6. The Database Query Service (backend) queries the database and returns the data to the Web Client.
      7. The Web Client (frontend) sends telecommands to the Telecommand Service.
      8. The Telecommand Service forwards the telecommands to the IO Service.
      9. The IO Service sends the telecommands to the Mission Device.
      ","tags":["Backend"]},{"location":"Backend%20Development/#getting-started","title":"Getting Started","text":"

      The most common way to write a backend service is to use TypeScript.

      Get started writing a backend service in TypeScript

      However, for some use cases, it may be necessary to write a backend service in other languages.

      You can even write a backend service in any language you want. The only requirement is that it can communicate with the NATS message bus. To learn how to write a service in other languages, see Using other languages.

      ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/","title":"Using other languages","text":"

      You can use any language you want to write your backend. The only requirement is that it can communicate with the NATS message bus.

      ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#implementation-requirements","title":"Implementation Requirements","text":"

      The only technical requirement for a backend service is that it can communicate with the NATS message bus. This means that it must be able to send and receive messages on the message bus.

      However, there are some additional standards that you should follow to make your service easier to use (and compliant with the Telestion ecosystem):

      ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#deployment","title":"Deployment","text":"

      Your service should be deployable as both a Docker container and as an executable. This makes it easier to deploy and scale your service.

      ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#configuration","title":"Configuration","text":"

      Your service should be configurable via environment variables.

      Every Telestion service receives at least the following environment variables:

      • NATS_URL: The URL of the NATS server
      • NATS_USER: The username of the NATS user
      • NATS_PASSWORD: The password of the NATS user
      • SERVICE_NAME: The name of the service. This is used to create a unique queue group for your service. See Queues for more information.
      • DATA_DIR: The path to the data directory. This is where your service should store any data it needs to persist. This is shared between multiple services. To ensure that your service doesn\u2019t overwrite data from other services, you should create a subdirectory for your service.

      If your service doesn\u2019t receive any of these environment variables, it should exit with a non-zero exit code.

      Warning

      There can be multiple instances of a service with the same name running at the same time. They are guaranteed to have the same configuration. If you need a truly unique identifier, you can combine the SERVICE_NAME and the process ID.

      ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#logging","title":"Logging","text":"

      Your service should log any \u201cfeedback\u201d to stdout and stderr.

      ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#queues","title":"Queues","text":"

      NATS allows you to create queue groups. This means that you can have multiple instances of the same service running, and they\u2019ll share the messages they receive.

      If you want to use this feature, you should use the SERVICE_NAME environment variable to create a unique queue group for your service.

      ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#message-body","title":"Message Body","text":"

      Your message must be able to handle, without crashing, the following types of messages:

      • JSON-encoded UTF-8 strings
      • Binary data

      Your service mustn\u2019t assume anything about the format or content of the message body. It must be able to handle any message body of the two types.

      ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#health-checks","title":"Health Checks","text":"

      Your service should provide a health check feature on the message bus subject __telestion__/health. This allows other services to check if your service is still running.

      While running, any Telestion service should respond (within 0.5 seconds) to requests on the __telestion__/health subject with a message containing the following JSON-encoded information:

      {\n    \"errors\": 0, // or number of \"recent\" errors\n    \"name\": \"My Service\" // the SERVICE_NAME\n}\n
      ","tags":["Backend"]},{"location":"Backend%20Development/other-languages/#service-behavior-specification","title":"Service Behavior Specification","text":"

      A formal description of the behavior of a Telestion service is provided in the Service Behavior Specification. It can be used to test libraries for writing Telestion services in other languages.

      ","tags":["Backend"]},{"location":"Backend%20Development/rust/","title":"Writing a Backend Service in Rust","text":"","tags":["Backend","Rust"]},{"location":"Backend%20Development/rust/#prerequisites","title":"Prerequisites","text":"
      • Rust
      • Cargo
      • NATS server
      • NATS client
      • Tokio
      ","tags":["Backend","Rust"]},{"location":"Backend%20Development/rust/#connecting-to-the-message-bus","title":"Connecting to the Message Bus","text":"
      use nats::asynk::Connection;\nuse std::error::Error;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn Error>> {\n    let nc = Connection::new(\"nats://localhost:4222\").await?;\n    let sub = nc.subscribe(\"bar\")?.with_handler(move |msg| {\n        println!(\"Received {}\", &msg);\n        Ok(())\n    });\n\n    Ok(())\n}\n
      ","tags":["Backend","Rust"]},{"location":"Backend%20Development/rust/#getting-configuration-from-the-environment","title":"Getting configuration from the environment","text":"
      [dependencies]\ndotenv = \"0.15.0\"\n
      use dotenv::dotenv;\nuse std::env;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn Error>> {\n    dotenv().ok();\n\n    let nats_url = env::var(\"NATS_URL\")?;\n    let nc = Connection::new(nats_url).await?;\n\n    Ok(())\n}\n
      ","tags":["Backend","Rust"]},{"location":"Backend%20Development/service-behavior/","title":"Service Behavior Specification","text":"

      Telestion services can be written in any language that supports the NATS protocol.

      While there can be differences in the implementation, there are some things that all Telestion services should have in common. This includes, among other things, the configuration of services, allowing seamless deployment of services written in different languages.

      "},{"location":"Backend%20Development/service-behavior/#gherkin","title":"Gherkin","text":"

      To specify these common behaviors, we use Gherkin. Gherkin is a language that is used to specify the behavior of software in a human-readable way while still being executable, meaning that tests can be automated.

      They are based on examples and should be written in a way that is independent of the implementation language.

      The Gherkin files are located in the backend-features directory of the Telestion project.

      "},{"location":"Backend%20Development/service-behavior/#documentation","title":"Documentation","text":"

      The Gherkin files get converted to Markdown files that are then included in the documentation.

      "},{"location":"Backend%20Development/service-behavior/auth/","title":"NATS authentication","text":""},{"location":"Backend%20Development/service-behavior/auth/#starting-the-service-with-valid-credentials","title":"Starting the service with valid credentials","text":"

      Given I have the basic service configuration

      And I have a NATS server running on \u201clocalhost:4222\u201d

      And the NATS server requires authentication

      And \u201cnats\u201d is a NATS user with password \u201cpassword\u201d

      And I have an environment variable named \u201cNATS_URL\u201d with value \u201clocalhost:4222\u201d

      And I have an environment variable named \u201cNATS_USER\u201d with value \u201cnats\u201d

      And I have an environment variable named \u201cNATS_PASSWORD\u201d with value \u201cpassword\u201d

      When I start the service

      Then the service should start

      And the service should connect to NATS.

      "},{"location":"Backend%20Development/service-behavior/auth/#starting-the-service-with-invalid-credentials-fails","title":"Starting the service with invalid credentials fails","text":"

      Given I have the basic service configuration

      And I have a NATS server running on \u201clocalhost:4222\u201d

      And the NATS server requires authentication

      And \u201cnats\u201d is a NATS user with password \u201cpassword\u201d

      And I have an environment variable named \u201cNATS_URL\u201d with value \u201clocalhost:4222\u201d

      And I have an environment variable named \u201cNATS_USER\u201d with value \u201cnats\u201d

      And I have an environment variable named \u201cNATS_PASSWORD\u201d with value \u201cwrong\u201d

      Then the service should fail to start.

      "},{"location":"Backend%20Development/service-behavior/auth/#starting-the-service-without-credentials-fails-when-the-authentication-is-required","title":"Starting the service without credentials fails when the authentication is required","text":"

      Given I have the basic service configuration

      And I have a NATS server running on \u201clocalhost:4222\u201d

      And the NATS server requires authentication

      And \u201cnats\u201d is a NATS user with password \u201cpassword\u201d

      And I have an environment variable named \u201cNATS_URL\u201d with value \u201clocalhost:4222\u201d

      Then the service should fail to start.

      "},{"location":"Backend%20Development/service-behavior/auth/#starting-the-service-fails-when-the-nats-server-is-offline","title":"Starting the service fails when the NATS server is offline","text":"

      Given I have the basic service configuration

      And I have a NATS server running on \u201clocalhost:4222\u201d

      And the NATS server requires authentication

      And \u201cnats\u201d is a NATS user with password \u201cpassword\u201d

      And I have an environment variable named \u201cNATS_URL\u201d with value \u201clocalhost:4222\u201d

      And I have an environment variable named \u201cNATS_USER\u201d with value \u201cnats\u201d

      And I have an environment variable named \u201cNATS_PASSWORD\u201d with value \u201cpassword\u201d

      And the NATS server is offline

      Then the service should fail to start.

      "},{"location":"Backend%20Development/service-behavior/config/","title":"Service Configuration","text":""},{"location":"Backend%20Development/service-behavior/config/#services-can-be-configured-through-environment-variables","title":"Services can be configured through environment variables","text":"

      The most common way to configure services is through environment variables. Environment variables are easy to use and can be set in a variety of ways. They are also easy to overwrite when running services locally.

      Given I have the basic service configuration

      And I have an environment variable named \u201cTEST\u201d with value \u201c1\u201d

      When I start the service without NATS

      Then the service should be configured with \u201cTEST\u201d set to \u201c1\u201d.

      "},{"location":"Backend%20Development/service-behavior/config/#services-can-be-configured-through-cli-arguments","title":"Services can be configured through CLI arguments","text":"

      Sometimes it is useful to configure services through CLI arguments. CLI arguments are easy to use and can be set when running services locally.

      Given I have the basic service configuration

      When I start the service with \u201c\u2013TEST=1\u201d without NATS

      Then the service should be configured with \u201cTEST\u201d set to \u201c1\u201d.

      "},{"location":"Backend%20Development/service-behavior/config/#trying-to-run-services-without-providing-the-required-configuration-fails","title":"Trying to run services without providing the required configuration fails","text":"

      There are some configuration values that are required for services to run. If these values are not provided, the service should fail to start. - NATS_URL - to connect to NATS - SERVICE_NAME - to group services in NATS when subscribing with multiple instances - DATA_DIR - a directory where the service is free to store persistent data

      During development, it is possible to use the development mode so you don\u2019t have to provide these values. However, this is not recommended for production.

      Given I have no service configuration

      Then the service should fail to start.

      "},{"location":"Backend%20Development/service-behavior/config/#cli-arguments-overwrite-environment-variables","title":"CLI arguments overwrite environment variables","text":"

      To make it easy to overwrite configuration values when running services locally, CLI arguments should overwrite environment variables.

      Given I have the basic service configuration

      And I have an environment variable named \u201cTEST\u201d with value \u201c1\u201d

      When I start the service with \u201c\u2013TEST=2\u201d without NATS

      Then the service should be configured with \u201cTEST\u201d set to \u201c2\u201d.

      "},{"location":"Backend%20Development/service-behavior/dev-mode/","title":"Development mode","text":""},{"location":"Backend%20Development/service-behavior/dev-mode/#the-service-can-be-started-in-dev-mode-to-use-default-parameters-during-development","title":"The service can be started in dev mode to use default parameters during development","text":"

      During development, it is useful to start the service with default parameters, so that it can be used without any configuration.

      Given I have no service configuration

      And I have a NATS server running on \u201clocalhost:4222\u201d

      When I start the service with \u201c\u2013dev\u201d without NATS

      Then the service should start

      And the service should be configured with \u201cNATS_USER\u201d set to \u201cundefined\u201d

      And the service should be configured with \u201cNATS_PASSWORD\u201d set to \u201cundefined\u201d.

      "},{"location":"Backend%20Development/service-behavior/dev-mode/#any-custom-configuration-overwrites-dev-mode-parameters","title":"Any custom configuration overwrites dev mode parameters","text":"

      Given I have no service configuration

      And I have a NATS server running on \u201clocalhost:4255\u201d

      And I have an environment variable named \u201cNATS_URL\u201d with value \u201clocalhost:4255\u201d

      When I start the service with \u201c\u2013dev \u2013DATA_DIR=/tmp\u201d

      Then the service should start

      And the service should connect to NATS

      And the service should be configured with \u201cDATA_DIR\u201d set to \u201c/tmp\u201d

      And the service should be configured with \u201cNATS_URL\u201d set to \u201clocalhost:4255\u201d.

      "},{"location":"Backend%20Development/service-behavior/nats/","title":"NATS Integration in Services","text":""},{"location":"Backend%20Development/service-behavior/nats/#the-service-has-access-to-the-nats-client-after-startup","title":"The service has access to the NATS client after startup","text":"

      The service should be able to access the NATS client after startup. This enables service developers to use the NATS client to publish and subscribe to messages.

      Given I have the basic service configuration

      And I have a NATS server running on \u201clocalhost:4222\u201d

      When I start the service

      Then the service should connect to NATS

      And the NATS connection API should be available to the service.

      "},{"location":"Backend%20Development/service-behavior/nats/#the-developer-disables-the-nats-integration","title":"The developer disables the NATS integration","text":"

      The developer may want to disable the NATS integration for testing purposes or because the service does not need NATS.

      Given I have the basic service configuration

      And I have a NATS server running on \u201clocalhost:4222\u201d

      When I start the service without NATS

      Then the service should not connect to NATS.

      "},{"location":"Backend%20Development/service-behavior/service/","title":"Service Lifecycle","text":""},{"location":"Backend%20Development/service-behavior/service/#starting-a-service","title":"Starting a service","text":"

      The most trivial scenario of them all. We start the service and it should start. That\u2019s it. No more, no less. But it\u2019s a good start.

      Given I have the basic service configuration

      And I have a NATS server running on \u201clocalhost:4222\u201d

      When I start the service

      Then the service should start.

      "},{"location":"Backend%20Development/typescript/","title":"Writing a Backend Service in TypeScript","text":"

      TypeScript is the recommended language for writing backend services. It is a superset of JavaScript that adds static typing and other features that make it easier to write and maintain code.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#prerequisites","title":"Prerequisites","text":"

      To write a backend service in TypeScript, you should be familiar with JavaScript and (ideally) TypeScript. Overall, basic JavaScript knowledge will be sufficient to get started, but async/await and Promises are used extensively for services, so you should be familiar with these topics.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#deno","title":"Deno","text":"

      Deno is a JavaScript/TypeScript runtime that is built on top of V8, Rust, and Tokio. It is a secure runtime for JavaScript and TypeScript.

      Compared to Node.js, Deno has the following advantages:

      • It has built-in TypeScript support
      • It has built-in security features
      • It\u2019s easier to deploy
      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#installing-deno","title":"Installing Deno","text":"

      To install Deno, please follow the instructions on the Deno website .

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#writing-a-basic-service","title":"Writing a basic Service","text":"","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#creating-a-new-service","title":"Creating a new Service","text":"

      Create a new directory for your service:

      mkdir my-service\ncd my-service\n

      Create a new file called service.ts:

      touch service.ts\n
      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#writing-the-service","title":"Writing the Service","text":"

      Open service.ts in your favorite editor and add the following code:

      service.ts
      import { startService } from 'https://deno.land/x/telestion/mod.ts';// (1)!\n\nawait startService/*(2)!*/({\n    nats: false,// (3)!\n});\n\nconsole.log('Hello World!');// (4)!\n
      1. Import the startService function from the library.
      2. Start the service. This automatically connects to NATS and does some other setup.
      3. Disable NATS. We don\u2019t need it for this example and it would otherwise throw an error because we haven\u2019t configured it yet.
      4. Log a message to the console when the service starts.
      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#running-the-service","title":"Running the Service","text":"

      To run the service, run the following command:

      deno run --allow-all service.ts --dev\n

      Success

      You should see the following output:

      Running in development mode. Using default values for missing environment variables.\nHello World!\n

      Running in development mode

      When you run the service with the --dev flag, the service will use default values for missing environment variables. You\u2019ll learn more about this in the configuration section.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/#next-steps","title":"Next Steps","text":"

      Now that you have a basic service running, you should have a look at how to make your service configurable.

      Read more about configuration

      If you prefer to learn by example, you can also have a look at the samples.

      Browse samples on GitHub

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/","title":"Service Configuration","text":"

      Tip

      Not every service needs to be configurable. If you are writing a simple service, you can skip this section.

      However, you can often save yourself a lot of time by making your service configurable. This way, you can use the same service in multiple environments without having to change the code.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#configuration-sources","title":"Configuration Sources","text":"

      Services can be configured using the following sources:

      • Environment variables
      • Command line arguments
      • An optional configuration file (JSON)

      All these sources get combined into a single configuration object. If a configuration value is defined in multiple sources, the following order is used:

      1. Command line arguments
      2. Environment variables
      3. Configuration file
      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#environment-variables","title":"Environment Variables","text":"

      Environment variables are the most common way to configure a service. They are easy to use and supported by most platforms.

      Environment variables are always strings. If you need to use a different type, you will have to parse the value yourself.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#command-line-arguments","title":"Command Line Arguments","text":"

      Command line arguments are useful for configuring a service during development. They are also useful for overriding configuration values when running a service in production.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#configuration-file","title":"Configuration File","text":"

      Configuration files are useful for configuring a service in production. They are also useful for overriding configuration values when running a service in production.

      Configuration files are optional. If no configuration file is provided, the service will still start.

      A configuration file is a JSON file with an object as its root element. The keys of this object are the configuration values. The values of this object are the configuration values.

      The configuration file is loaded from the path passed as CONFIG_FILE as either environment variable or command line argument.

      You can optionally also pass a CONFIG_KEY to load a specific key from the configuration file. This is useful if you want to use the same configuration file for multiple services.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#configuration-precedence-overview-diagram","title":"Configuration Precedence Overview Diagram","text":"
      graph TB\n    accTitle: Diagram of the configuration sources and their order of precedence. Text description in collapsed section below.\n    A[Environment Variables] --merged into--> C[Preliminary Configuration]\n    B[Command line arguments] --merged into with priority--> C\n    C -.CONFIG_FILE.-> D[Configuration File]\n    D --merged into--> E[Configuration Object]\n    C --merged into with priority--> E

      Configuration sources and their order of precedence.

      Text Description
      1. Environment variables are merged into the preliminary configuration.
      2. Command line arguments are merged into the preliminary configuration with priority.
      3. The configuration file is loaded (based on the CONFIG_FILE parameter of the preliminary configuration) and merged into the preliminary configuration.
      4. The preliminary configuration is merged into the configuration object with priority.
      5. The configuration object gets returned.
      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#minimal-configuration-values","title":"Minimal Configuration Values","text":"

      Some configuration values are required for all services. These values are:

      • NATS_URL: The URL of the NATS server to connect to.
      • NATS_USER (if the NATS server requires authentication): The username to use when connecting to NATS.
      • NATS_PASSWORD (if the NATS user requires authentication): The password to use when connecting to NATS.
      • SERVICE_NAME: The name of the service. This is used to identify the service in the logs and in the NATS server. This is required for all services.
      • DATA_DIR: The directory where the service can store data. This is required for all services.

      Tip

      To make it easier to run your service during development, sensible defaults are used when you pass the --dev flag to the service:

      Configuration Value Default Value NATS_URL localhost:4222 NATS_USER (none) NATS_PASSWORD (none) SERVICE_NAME dev-[process gid] DATA_DIR ./data

      This way, you don\u2019t have to set all the required configuration values when running the service locally.

      Without the --dev flag, the service fails if any of the required configuration values are missing.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/configuration/#accessing-the-configuration","title":"Accessing the Configuration","text":"

      Now that you know about the different configuration sources, let\u2019s see how you can access the configuration in your service. Since the complicated bits are handled by the startService function, this is actually pretty straight forward.

      Create a file called config.json next to your service.ts file with the following content:

      config.json
      {\n  \"SERVICE_NAME\": \"Config Tester\",\n  \"tasks\": {\n    \"task1\": \"Task 1\",\n    \"task2\": \"Task 2\"\n  }\n}\n

      Now, let\u2019s adjust the service.ts file to use the configuration:

      service.ts
      import { startService } from \"https://deno.land/x/telestion/mod.ts\";\nimport { z } from \"https://deno.land/x/zod@v3.21.4/mod.ts\";// (1)!\n\nconst { config: rawConfig/* (2)! */} = await startService({\n  nats: false,\n});\n\nconst config = z.object({\n  NAME: z.string(),\n  tasks: z.record(z.string(), z.string()),\n}).parse(rawConfig);// (3)!\n\nconsole.log(config.NAME, config.tasks);// (4)!\n
      1. Import the z function from the Zod to validate the configuration. Never assume the configuration is valid. Always validate it before using it.
      2. Save the raw configuration in a variable called rawConfig.
      3. Validate the configuration using Zod. This will throw an error if the configuration is invalid.
      4. You can now safely use the configuration in your service. If the configuration is invalid, the service will not start.

      Now, let\u2019s see what happens if we run the service:

      deno run --allow-all service.ts --dev\n

      As expected, the service doesn\u2019t start:

      $ deno run --allow-all service.ts --dev\nRunning in development mode.\nUsing default values for missing environment variables.\nerror: Uncaught ZodError: [\n  {\n    \"code\": \"invalid_type\",\n    \"expected\": \"string\",\n    \"received\": \"undefined\",\n    \"path\": [\n      \"NAME\"\n    ],\n    \"message\": \"Required\"\n  },\n  {\n    \"code\": \"invalid_type\",\n    \"expected\": \"object\",\n    \"received\": \"undefined\",\n    \"path\": [\n      \"tasks\"\n    ],\n    \"message\": \"Required\"\n  }\n]\n

      Let\u2019s fix this by passing the required configuration values:

      deno run --allow-all service.ts --dev \\\n  --CONFIG_FILE ./config.json \\ # (1)!\n  --NAME \"Hello\" # (2)!\n
      1. Pass the path to the configuration file using the --CONFIG_FILE flag.
      2. Pass the NAME configuration value using the --NAME flag.

      Now, everything works as expected.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/e2e-log-service/","title":"End to end example: Log Service","text":"

      Note

      The author generated this text in part with GPT-3, OpenAI\u2019s large-scale language-generation model. Upon generating draft language, the author reviewed, edited, and revised the language to their own liking and takes ultimate responsibility for the content of this publication.

      This tutorial will explain step-by-step how to write a log service that will listen for messages on the log.> subject and write them to a file.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/e2e-log-service/#steps","title":"Steps","text":"
      1. First, we need to import the startService function from our library (lib.ts) and the encode function from the standard Deno library.

        import { startService } from \"https://deno.land/x/telestion/mod.ts\";\nimport { encode } from \"https://deno.land/std@0.186.0/encoding/hex.ts\";\nimport { resolve } from \"https://deno.land/std@0.186.0/path/mod.ts\";\n
      2. Next, we create a new TextEncoder instance. This will be used to turn messages into a format that can be written to a file.

        const encoder = new TextEncoder();\n
      3. We then call the startService function to set up our service. This will return an object containing information about the message bus that we can use to subscribe to messages.

        const { messageBus, dataDir } = await startService();\n
      4. We then resolve the log file path and create its parent directory if it doesn\u2019t exist yet.

        const logFilePath = resolve(dataDir, \"log.txt\");\nawait Deno.mkdir(dataDir, { recursive: true });\n
      5. We then subscribe to the message bus, using a wildcard subscription for any messages published on the log.> subject. This will allow us to receive all messages published on any topics starting with log..

        const logMessages = messageBus.subscribe(\"log.>\");\n
      6. We use a for-await-of loop to receive messages from the message bus. For each message, we extract the subject (split the string on ., then take the second element) and the message data, which we encode using the encode function from the standard library.

        for await (const msg of logMessages) {\n  try {\n    const currentTime = new Date().toISOString();\n    const logMessage = encode(msg.data).toString();\n    const subject = msg.subject.split(\".\")[1];\n
      7. We log the message to the console and write it to a file (appending it to the end).

            console.log(`${currentTime} [${subject}] ${logMessage}`);\n    await Deno.writeFile(\n      logFilePath,\n      encoder.encode(`${currentTime} [${subject}] ${logMessage}\\n`),\n      { append: true },\n    );\n  } catch (error) {\n    console.error(error);\n  }\n}\n

      And that\u2019s it! Our service is now complete and ready to be used.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/e2e-log-service/#final-code","title":"Final Code","text":"
      import { startService } from \"https://deno.land/x/telestion/mod.ts\";\nimport { encode } from \"https://deno.land/std@0.186.0/encoding/hex.ts\";\nimport { resolve } from \"https://deno.land/std/0.186.0/path/mod.ts\";\n\nconst encoder = new TextEncoder();\n\nconst { messageBus, dataDir } = await startService();\n\nconst logFilePath = resolve(dataDir, \"log.txt\");\nawait Deno.mkdir(dataDir, { recursive: true });\n\nconst logMessages = messageBus.subscribe(\"log.>\");\n\nfor await (const msg of logMessages) {\n  try {\n    const currentTime = new Date().toISOString();\n    const logMessage = encode(msg.data).toString();\n    const subject = msg.subject.split(\".\")[1];\n\n    console.log(`${currentTime} [${subject}] ${logMessage}`);\n    await Deno.writeFile(\n      logFilePath,\n      encoder.encode(`${currentTime} [${subject}] ${logMessage}\\n`),\n      { append: true },\n    );\n  } catch (error) {\n    console.error(error);\n  }\n}\n
      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/","title":"Interacting with the Message Bus","text":"

      The message bus is a simple, lightweight, and fast way to send messages between different parts (services) of your application. It is a simple publish/subscribe system that allows you to send messages to a specific subject and have any listeners on that subject receive the message.

      Running NATS for development

      Now that we want to interact with the message bus, we need to have NATS running. If you\u2019re using the --dev mode for testing your service, it\u2019s sufficient to run the nats-server executable in a separate terminal window. This will start a local NATS server on port 4222 which is the default port for NATS.

      If you have a prdouction-like setup, you\u2019ll need to pass the NATS_USER and NATS_PASSWORD corresponding to your NATS configuration as configuration parameters to your service for authentication.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#connecting-to-the-message-bus","title":"Connecting to the Message Bus","text":"

      Connecting to the event bus is automatically handled by the startService function. It will connect to the message bus using the NATS_URL environment variable. If you\u2019re running the service in --dev mode, this will be nats://localhost:4222 by default.

      All you need to do compared to the previous examples is to omit the { nats: false } parameter from the startService function call:

      service.ts
      import {\n    startService\n} from \"https://deno.land/x/telestion/mod.ts\";\n\nconst {nc/* (1)! */} = await startService(/* (2)! */);\n
      1. Store the NATS connection in a variable called nc for later use.
      2. Omit the { nats: false } parameter from the startService function call since we want to connect to the message bus.

      Note

      startService actually returns an object containing the NATS connection (nc) and a few other things. In our example, we use destructuring to only get the nc variable. This is equivalent to the following code:

      const service = await startService();\nconst nc = service.nc;\n
      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#publishing-messages","title":"Publishing Messages","text":"

      Publishing messages is as simple as calling the publish function on the NATS connection:

      await nc.publish(\"subject\"/*(1)!*/, message/*(2)!*/);\n
      1. The subject (sometimes also called channel) to which the message gets published.
      2. The message data (also called payload or body).

      However, Telestion Hub uses a specific message format for all messages sent over the message bus. A message can be either JSON or a binary message. The binary message is used for sending large amounts of data, e.g., images or video streams. The JSON message is used for all other messages.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#json-messages","title":"JSON Messages","text":"

      To send a JSON message, you need to create a JSON object and pass it to the publish function:

      service.ts
      import {\n    JSONCodec,\n    startService\n} from \"https://deno.land/x/telestion/mod.ts\";\n// or: import { JSONCodec } from \"https://deno.land/x/nats/src/mod.ts\";\n\nconst {nc} = await startService();\n\nconst jsonCodec = JSONCodec();//(2)!\n\nawait nc.publish(\"subject\", jsonCodec.encode/*(3)!*/({\n    foo: \"some arbitrary JSON-compatible data\",\n    bar: 42\n}));\n
      1. Import the JSONCodec (for convenience, this gets re-exported by the lib.ts, but you can also import it directly from the NATS library).
      2. Create a new JSONCodec instance.
      3. Encode the JSON object using the JSONCodec instance.
      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#binary-messages","title":"Binary Messages","text":"

      To send a binary message, you need to create a Uint8Array containing the bytes and pass it to the publish function:

      service.ts
      import {\n    startService\n} from \"https://deno.land/x/telestion/mod.ts\";\n\nconst {nc} = await startService();\n\nawait nc.publish(\"subject\", new Uint8Array([0x01, 0x02, 0x03]));\n

      Uint8Arrays

      You can learn more about how you can use Uint8Array on MDN.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#subscribing-to-messages","title":"Subscribing to Messages","text":"

      There are multiple ways to subscribe to messages on a subject. The most common way is to use the subscribe function in combination with a for await loop:

      service.ts
      import {\n    startService\n} from \"https://deno.land/x/telestion/mod.ts\";\n\nconst {nc} = await startService();\n\nconst subjectSubscription/*(1)!*/ = await nc.subscribe(\"subject\"/*(2)!*/);\n\nfor await (const message of subjectSubscription) {//(3)!\n    console.log(message.data);//(4)!\n}\n
      1. Store the subscription in a variable called subjectSubscription for later use.
      2. Subscribe to the subject subject.
      3. For each message received on the subject, \u2026
      4. \u2026 print the message data to the console.

      Unfortunately, this won\u2019t decode our JSON messages automatically. We need to do this ourselves:

      service.ts
      import {\n    JSONCodec,\n    startService\n} from \"https://deno.land/x/telestion/mod.ts\";\n\nconst {nc} = await startService();\n\nconst jsonCodec = JSONCodec();\n\nconst subjectSubscription = await nc.subscribe(\"subject\");\nfor await (const message of subjectSubscription) {\n    const jsonMessage = jsonCodec.decode(message.data);//(1)!\n    console.log(jsonMessage.foo);//(2)!\n}\n
      1. Decode the message data using the JSONCodec instance.
      2. Print the foo property of the decoded JSON message to the console.

      Danger

      Can you spot the problem with this code? What happens if the message data doesn\u2019t contain a foo property? Or if it\u2019s not a JSON message at all? This would lead to our service crashing!

      Never assume a message\u2019s structure!

      You should always validate the message data before using it. We\u2019ll cover this in the next section.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#validating-messages","title":"Validating Messages","text":"

      A Telestion service must validate all messages it receives. This is to ensure that the service doesn\u2019t crash when it receives invalid messages.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#validating-the-message-type","title":"Validating the message type","text":"

      The first \u201clayer\u201d of validation is the message type. A message can either be a JSON message or a binary message. The jsonCodec.decode function will throw an error if the message data is not a valid JSON message. Therefore, we can use a try/catch block to catch the error and handle it accordingly:

      service.ts
      // ...\n\nfor await (const message of subjectSubscription) {\n    try/*(3)!*/{\n        const jsonMessage = jsonCodec.decode(message.data);\n        console.log(jsonMessage.foo);\n    } catch (_e) {\n        console.error/*(2)!*/(\"Received invalid message:\", message);\n    }\n}\n
      1. Catch the error thrown by jsonCodec.decode.
      2. Print the error message to the console (or do whatever else you want to do when you receive an invalid message).
      3. Wrap the code that decodes the message in a try/catch block.

      Binary Messages

      Since any messages get sent as binary messages (in fact, the JSONCodec does nothing else than convert the JSON message to a Uint8Array and back), there\u2019s no way to validate that a message is supposed to be a binary message. This makes the next section even more important.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#validating-the-message-structure","title":"Validating the message structure","text":"

      The second \u201clayer\u201d of validation is the message structure. This is where you validate that the message data contains all the properties you expect it to contain. For example, if you expect a message to contain a foo property, you must verify its existence before using it.

      For structured JSON data, we recommend that you use the zod library for validation. This is also used in our lib.ts file to validate the configuration. You can find more information about zod in the library\u2019s GitHub repository.

      Let\u2019s create a zod schema for our JSON message in a new file called foo-message.ts:

      foo-message.ts
      import {\n    z\n} from \"https://deno.land/x/zod@v3.16.1/mod.ts\";\n\nexport const fooMessageSchema = z.object/*(1)!*/(({\n    foo: z.string()/*(2)!*/,\n    bar: z.number().min(-10)/*(3)!*/\n});\n\nexport type FooMessage = z.infer<typeof fooMessageSchema>;//(4)!\n
      1. A FooMessage must be an object.
      2. A FooMessage must have a foo property that is a string.
      3. A FooMessage must have a bar property that is a number and is greater than or equal to -10.
      4. This is a TypeScript type that represents the FooMessage type. While we won\u2019t use it in this example, it\u2019s good practice to create a type for each schema you create. This allows you to use the type anywhere in your code:
        function foo(message: FooMessage) {\n     console.log(message.foo);\n}\n\n// ...\n\nconst fooMessage = fooMessageSchema.parse(\n     jsonCodec.decode(message.data)\n);\nfoo(fooMessage); // This works now!\n

      Now we can use this schema to validate the message data:

      service.ts
      import {\n    fooMessageSchema\n} from \"./foo-message.ts\";\n\n// ...\n\nfor await (const message of subjectSubscription) {\n    try {\n        const jsonMessage = fooMessageSchema.parse/*(1)!*/(\n            jsonCodec.decode(message.data)\n        );\n\n        console.log(jsonMessage/*(2)!*/.foo);\n    } catch (_e) {\n        console.error(\"Received invalid message:\", message);\n    }\n}\n
      1. Validate the message data using the fooMessageSchema schema. This will throw an error if the message data doesn\u2019t match the schema.
      2. TypeScript now knows that jsonMessage is a valid FooMessage object. Therefore, we can access the foo property without any problems.

      Success

      If your editor has great TypeScript support and has shown you warnings/errors before, they are now gone! This is because TypeScript now knows that the jsonMessage variable is a valid FooMessage object. In other words, your code is now safe from invalid messages!

      Binary Messages

      For binary messages, you can\u2019t use zod to validate the message structure. Instead, you should use the Uint8Array methods to validate the message structure. For example, you can check the length of the message data using the length property of the Uint8Array:

      if (message.data.length !== 3) {\n    console.error(\"Received invalid message:\", message);\n}\n

      However, the exact validation required completely depends on your use case. Just make sure that your code doesn\u2019t crash when it receives an invalid message.

      ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#subscribing-to-multiple-topics","title":"Subscribing to Multiple Topics","text":"

      So far, we\u2019ve used the for await loop. This is a convenient way to subscribe to a single topic. However, if you want to do more than just react to messages from a specific subject, we get into trouble. Since the for await loop is blocking, we can\u2019t do anything else while we\u2019re waiting for messages.

      We can solve this by wrapping the for await loop in an async function and calling it in a separate thread. This allows us to do other things while we\u2019re waiting for messages:

      service.ts
      // ...\n\nconst subjectMessages = nc.subscribe(\"foo\");\n(async () => {//(1)!\n    for await (const message of subjectMessages) {\n        // Handle messages from the \"foo\" subject\n    }\n})();\n\n// ... (2)\n
      1. Wrap the for await loop in an async function and call it immediately. This will start the subscription in parallel to the rest of the code.
      2. Do other things while we\u2019re waiting for messages.

      Note that we\u2019re storing the return value of nc.subscribe in a variable outside the async function. This is important so that we can close the subscription or check its status later.

      Closing the Subscription

      You can close the subscription by calling the unsubscribe method on the subscription object:

      const subjectMessages = nc.subscribe(\"foo\");\n// ...\nsubjectMessages.unsubscribe();\n

      You must call unsubscribe on the subscription object. Calling nc.unsubscribe will unsubscribe from all subscriptions!

      This now allows us to subscribe to multiple topics:

      service.ts
      // ...\n\nconst fooMessages = nc.subscribe(\"foo\");//(1)!\n(async () => {\n    for await (const message of fooMessages) {\n        // Handle messages from the \"foo\" subject\n    }\n})();\n\nconst barMessages = nc.subscribe(\"bar\");//(2)!\n(async () => {\n    for await (const message of barMessages) {\n        // Handle messages from the \"bar\" subject\n        if (shouldUnsubscribeFoo(message))\n            fooMessages.unsubscribe/*(3)!*/();\n\n        if (shouldUnsubscribeBar(message))\n            barMessages.unsubscribe/*(4)!*/();\n    }\n})();\n\nawait Promise.all/*(5)!*/([\n    fooMessages.closed,\n    barMessages.closed\n]);\n\nconsole.log(\"All subscriptions closed!\");//(6)!\n
      1. Subscribe to the foo subject.
      2. Subscribe to the bar subject (in parallel to the foo subscription).
      3. Unsubscribe from the foo subject if the shouldUnsubscribeFoo function returns true.
      4. Unsubscribe from the bar subject if the shouldUnsubscribeBar function returns true.
      5. Wait for both subscriptions to close. This will happen when the unsubscribe method is called on the subscription object.

        The closed property is a Promise that resolves when the subscription is closed.

        Promise.all is a convenient way to wait for multiple promises to resolve. It returns a Promise that resolves when all promises passed to it have resolved.

      6. Log a message when both subscriptions are closed.
      7. ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#queue-groups","title":"Queue Groups","text":"

        Info

        Queue groups are a way to distribute messages between multiple subscribers. If you have multiple subscribers to a subject, you can use queue groups to distribute messages between them. This is useful if you want to distribute messages between multiple instances of a service (for example, if you want to scale your service horizontally because processing a message takes too long).

        All you have to do to use queue groups is to pass a queue option to the subscribe method. You can use any string as the queue name, but by its definition, the SERVICE_NAME configuration parameter works perfect for this. For convenience, this gets exposed as serviceName on the object returned by startService:

        service.ts
        // ...\n\nconst {\n    nc,\n    serviceName/*(1)!*/\n} = await startService();\n\nconst fooMessages = nc.subscribe(\n    \"foo\", \n    {queue: serviceName/*(2)!*/}\n);\n(async () => {\n    for await (const message of fooMessages) {\n        // Handle messages from the \"foo\" subject\n    }\n})();\n\n// ...\n
        1. Get the serviceName from the object returned by startService.
        2. Pass the serviceName as the queue option to the subscribe method.

        If you now run multiple instances of your service, you\u2019ll see that messages are distributed between them. This is because the queue option tells the message bus to distribute messages between all subscribers with the same queue name.

        Service names in development mode

        When you run your service in development mode, the serviceName will be generated. This means that you\u2019ll get a different service name every time you start your service. To avoid this, you can either set the SERVICE_NAME environment variable or pass a service name via the CLI:

        deno run --allow-all service.ts --dev --SERVICE_NAME=foo\n
        ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#wildcards","title":"Wildcards","text":"

        Wildcards are a way to subscribe to multiple subjects at once. This is useful if you want to subscribe to multiple subjects that have a common prefix. For example, you could have a service that handles all requests to the /api endpoint. You could then subscribe to all requests to the /api endpoint by subscribing to the api.> subject.

        There are two types of wildcards: * and >. The * wildcard matches a single token. The > wildcard matches one or more tokens. For example, the api.* subject matches api.foo and api.bar, but not api.foo.bar. The api.> subject matches api.foo, api.bar, and api.foo.bar.

        You can use wildcards in the subscribe method and then use the subject property of the message to check which subject the message was sent to:

        service.ts
        // ...\n\n/**\n * A simple key-value store.\n */\nconst store: Record<string, unknown> = {};\n\nconst kvMessages = nc.subscribe/*(1)!*/(\"kv.>\");\n(async () => {\n    for await (const message of kvMessages) {\n        try {\n            const [_kv, action, ...keyParts] =\n                message.subject.split/*(2)!*/(\".\");\n\n            const key = keyParts.join(\".\");\n\n            if (action === \"get\") {\n                // retrieve the value from the store\n                message.respond(\n                    jsonCodec.encode(store[key])\n                );\n            } else if (action === \"set\") {\n                // set the value in the store\n                store[key] = jsonCodec.decode(message.data);\n                message.respond(jsonCodec.encode({ok: true});\n            }\n        } catch (error) {\n            message.respond(\n                jsonCodec.encode({error: error.message})\n            );\n        }\n    }\n})();\n
        1. Subscribe to the kv.> subject. This matches all subjects that start with kv..
        2. Split the subject into tokens. The first token is kv, the second token is the action, and the rest of the tokens are the key. We store these into variables using array destructuring.

        In this example, we subscribe to the foo.* subject. We then use the subject property of the message to check which action was requested. If the action is get, we get the value from the store object and respond with it. If the action is set, we set the value in the store object.

        For example, if we send a message to the foo.get.bar subject, we\u2019ll get the value of the bar key in the store object. If we send a message to the foo.set.bar subject with the value 42, we\u2019ll set the value of the bar key in the store object to 42.

        Success

        Woohoo! You\u2019ve just re-implemented a key-value store using the message bus, which (with a few convenience features on top) is an essential part of Telestion\u2019s standard services!

        ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#requestreply","title":"Request/Reply","text":"

        So far, we\u2019ve looked at publishing messages and subscribing to messages. However, there\u2019s one more thing we can do with the message bus: request/reply.

        Request/reply is a pattern where one service sends a request to another service and waits for a response. This is useful if you want to get data from another service. For example, you could have a service that stores data in a database. Other services can then request data from this service.

        ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#sending-a-request","title":"Sending a Request","text":"

        Let\u2019s start by looking at how we can send a request. We can use the request method on the NatsConnection object to send a request. This makes it incredibly easy to send a request:

        service.ts
        // ...\n\nconst response = await nc.request/*(1)!*/(\n    \"fooRequest\"/*(2)!*/,\n    jsonCodec.encode({foo: \"bar\"})/*(3)!*/\n);\nconsole.log(response.data);\n
        1. Call the request method on the NatsConnection object. This method returns a Promise that resolves when the response is received. The response has the same form as the messages we\u2019ve already seen in our for await loops.
        2. Specify the subject to send the request to.
        3. Encode the request message data using the jsonCodec codec. This is the same as we\u2019ve done before.

        Tip: Specifying a timeout

        As it is, our code will wait forever for a response. This is probably not what we want. We can specify a timeout by passing a second argument to the request method:

        const response = await nc.request(\n    \"fooRequest\", \n    jsonCodec.encode({foo: \"bar\"}),\n    {timeout: 1000}\n);\n

        This will cause the request method to reject the Promise if no response is received within 1000 milliseconds. Make sure to handle the rejection by handling it appropriately.

        ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#handling-a-request","title":"Handling a Request","text":"

        Now that we know how to send a request, let\u2019s look at how we can handle a request. We can use the subscribe method on the NatsConnection object to subscribe to a subject. This allows us to handle requests:

        service.ts
        // ...\n\nconst requestMessages = nc.subscribe/*(1)!*/(\"fooRequest\");\n\n(async () => {\n    for await (const message of requestMessages) {//(2)!\n        message.respond/*(3)!*/(jsonCodec.encode({bar: \"baz\"}));\n    }\n})();\n
        1. Subscribe to the fooRequest subject as usual.
        2. Iterate over the messages received from the fooRequest subject as usual.
        3. Respond to the request by calling the respond method on the message object. This method takes a single argument: the response message data. This is the same as we\u2019ve done before.

        Tip

        The message received from the fooRequest subject is the same as the message received from the foo subject. This means that we can use the same steps to handle the message as we\u2019ve done before if we need the data to handle the request.

        ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/message-bus/#related-links","title":"Related Links","text":"

        While we\u2019ve covered the basics of interacting with the message bus in this article, there are a few more things you can do with the message bus. You can find more information about the message bus in the NATS documentation. While the connection to the message bus is handled by the startService function, topics like receiving and sending messages are covered more extensively (including useful concepts like request/reply, queue groups, etc.) in the NATS documentation.

        ","tags":["Backend","TypeScript"]},{"location":"Backend%20Development/typescript/samples/","title":"Samples","text":"

        You can find even more samples in the project\u2019s GitHub repository under backend-deno/samples:

        Browse samples on GitHub

        "},{"location":"Backend%20Development/typescript/samples/#running-the-samples","title":"Running the samples","text":"

        You can run all the samples using the docker-compose.yml file in the linked folder. Just run the following command:

        docker-compose up\n

        This will run all the samples, including the required NATS server.

        "},{"location":"Deployment/","title":"Deployment","text":"

        Deployment is the process of making a software system available for use. In the context of Telestion, deployment refers to the process of making the Telestion application available for use.

        Warning

        The deployment process is heavily dependent on the specific use case. The following documentation is intended to give a general overview of the deployment process that\u2019s available by default in new Telestion Projects.

        Depending on your project, you may need to adapt the deployment process to your specific needs.

        ","tags":["Deployment"]},{"location":"Deployment/#deployment-methods","title":"Deployment Methods","text":"

        Telestion can be deployed in multiple ways:

        • Local Deployment
        • Docker Deployment
        • Kubernetes Deployment

        Info

        The local deployment is the easiest way to get started with Telestion. You should probably start with the local deployment and then move on to the other deployment methods as needed.

        ","tags":["Deployment"]},{"location":"Deployment/#nats-and-its-configuration","title":"NATS and its configuration","text":"

        Telestion uses NATS as its message broker. NATS is a lightweight, high-performance cloud-native messaging system. It is used for the communication between the Telestion backend and the Telestion frontend.

        No matter which deployment method you choose, you need to configure NATS. The configuration of NATS is described in the NATS Configuration document.

        ","tags":["Deployment"]},{"location":"Deployment/concepts/","title":"Concepts","text":"

        This document describes the pre-requisites for deploying Telestion on your local machine.

        ","tags":["Deployment"]},{"location":"Deployment/concepts/#docker","title":"Docker","text":"

        Docker is a containerization platform that allows you to package your application and all its dependencies together in the form of containers to ensure that your application works seamlessly in any environment be it development or test or production.

        ","tags":["Deployment"]},{"location":"Deployment/concepts/#docker-compose","title":"Docker Compose","text":"

        Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application\u2019s services. Then, with a single command, you create and start all the services from your configuration.

        ","tags":["Deployment"]},{"location":"Deployment/concepts/#kubernetes","title":"Kubernetes","text":"

        Info

        Kubernetes is not required for deploying Telestion. It\u2019s mostly relevant for big production deployments.

        Kubernetes is an open source container-orchestration system for automating computer application deployment, scaling, and management.

        ","tags":["Deployment"]},{"location":"Deployment/concepts/#web-server","title":"Web Server","text":"

        Info

        For Telestion, a web server is required to serve the frontend application to the user.

        A web server is server software, or hardware dedicated to running said software, that can satisfy web client requests. A web server can, in general, contain one or more websites. A web server processes incoming network requests over HTTP and several other related protocols.

        ","tags":["Deployment"]},{"location":"Deployment/concepts/#nats","title":"NATS","text":"

        Info

        Telestion uses NATS as a message broker. It\u2019s required for the communication between the Telestion services (both backend and frontend).

        NATS is a simple, secure and high-performance open source messaging system for cloud native applications, IoT messaging, and microservice architectures.

        ","tags":["Deployment"]},{"location":"Deployment/docker/","title":"Docker Deployment","text":"

        This document describes how to deploy Telestion using Docker.

        "},{"location":"Deployment/docker/#guidelines","title":"Guidelines","text":"

        These guidelines are not strict rules, but they are recommended to follow. If you have a good reason to deviate from them, feel free to do so. Or in other words: If you don\u2019t know why you should deviate from them, don\u2019t do it.

        "},{"location":"Deployment/docker/#images-per-service-type","title":"Images per Service Type","text":"

        Depending on your project, it might make sense to have individual images for each service. However, for smaller projects, this is often both unnecessary and cumbersome. In this case, it is recommended to have one image for all services of a specific type.

        For example, you would have one image for all Deno based Backend services, one for the frontend, and so on. This way, you won\u2019t have to build and push huge numbers of images, and you can still use the same image for all services of a specific type.

        "},{"location":"Deployment/docker/#dependency-installation-at-build-time","title":"Dependency Installation at Build Time","text":"

        If you have a service that requires dependencies to be installed, it is recommended to do so at build time. This way, you can be sure that the dependencies are installed when the image is built, and you don\u2019t have to wait for them to be installed when the container is started.

        This ensures both a faster startup time and a consistent execution environment.

        "},{"location":"Deployment/kubernetes/","title":"Kubernetes Deployment","text":"

        This document describes how to deploy Telestion using Kubernetes.

        (Work in progress)

        "},{"location":"Deployment/local/","title":"Local Deployment","text":"

        Telestion can be deployed locally on your machine. This can have several reasons, for example:

        • You want to test your application before deploying it to a server
        • You want to develop an application and test it locally
        • You want to run Telestion on a machine without internet connection
        • You want to run Telestion on a machine without Docker/Kubernetes
        • You need to access the machine directly (for example, for CAN bus access)

        Note

        It\u2019s a common tactic to have most Telestion services running in a cloud environment and only the services that need direct access to the machine running locally.

        This is easy to achieve thanks to NATS and means that you can have the best of both worlds.

        ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-nats/","title":"Deploying NATS","text":"

        NATS isn\u2019t complicated to deploy. This guide will show you how to deploy NATS locally.

        ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-nats/#installing-nats","title":"Installing NATS","text":"

        Download the NATS server from the NATS download page.

        ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-nats/#running-nats","title":"Running NATS","text":"

        Run the NATS server with the following command:

        nats-server\n
        ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-nats/#configuring-nats","title":"Configuring NATS","text":"

        NATS can be configured using a configuration file. To run NATS with a configuration file, use the following command:

        nats-server -c <path-to-config-file>\n

        As a starting point, you can use the following configuration to enable everything you need while developing:

        nats.conf
        http_port: 8222\n\nwebsocket: {\n     port: 9222\n     no_tls: true\n}\n

        This will enable the HTTP and WebSocket interfaces.

        Note that for production deployments, you need to configure NATS to use TLS and set up proper authentication. You can learn more about configuring NATS in the NATS configuration guide.

        Learn more about NATS configuration

        ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/","title":"Deploying TypeScript services","text":"","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/#deploying-a-single-service","title":"Deploying a single service","text":"

        (coming soon)

        ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/#deploying-multiple-services-using-the-process-manager-pup","title":"Deploying multiple services using the process manager pup","text":"

        The process manager pup is a tool that can be used to run multiple services at once without having to manually start each service. It also makes it easy to manage the running services.

        ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/#installing-pup","title":"Installing pup","text":"

        Install pup using the following command:

        deno install -Afr https://deno.land/x/pup/pup.ts\n
        ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/#configuring-pup","title":"Configuring pup","text":"

        In your project\u2019s root directory, create a file called pup.jsonc with the following contents:

        {\n  \"services\": [\n    {\n      \"name\": \"service1\",\n      \"command\": \"deno run --allow-net --allow-env service1.ts\",\n      \"env\": {\n        \"SERVICE_NAME\": \"service1\",\n        \"NATS_URL\": \"nats://localhost:4222\",\n        \"NATS_USER\": \"service\",\n        \"NATS_PASSWORD\": \"service\"\n      }\n    },\n    {\n      \"name\": \"service2\",\n      \"command\": \"deno run --allow-net --allow-env service2.ts\",\n      \"env\": {\n        \"SERVICE_NAME\": \"service1\",\n        \"NATS_URL\": \"nats://localhost:4222\",\n        \"NATS_USER\": \"service\",\n        \"NATS_PASSWORD\": \"service\"\n      }\n    }\n  ]\n}\n
        ","tags":["Deployment","Local"]},{"location":"Deployment/local/local-typescript-service/#running-pup","title":"Running pup","text":"

        Run pup using the following command:

        pup -c pup.jsonc run\n

        This will start the pup runner. To start the services, run the following command:

        pup -c pup.jsonc start all\n

        Tip

        If you want to have a service starting immediately after the runner starts, you can add \"autostart\": true to that service\u2019s configuration.

        To stop the services, run the following command:

        pup -c pup.jsonc stop all\n

        Tip

        You can also stop a single service by specifying its name instead of all.

        You can get the status of the services using the following command:

        pup -c pup.jsonc status\n

        Tip: Running NATS through pup

        You can even run NATS through pup. Just add the following service to your pup.jsonc file:

        {\n  \"name\": \"nats\",\n  \"command\": \"nats-server -c <path-to-config-file>\",\n  \"env\": {}\n}\n

        You can find more information about pup on their documentation page.

        ","tags":["Deployment","Local"]},{"location":"Deployment/nats/","title":"NATS Server Configuration","text":"

        The NATS server can be configured using both a configuration file and environment variables.

        "},{"location":"Deployment/nats/#environment-variables","title":"Environment Variables","text":"

        The NATS server configuration is done via environment variables. The following table lists all available environment variables and their default values.

        Environment Variable Default Value Description NATS_HOST localhost The host of the NATS server. NATS_PORT 4222 The port of the NATS server."},{"location":"Deployment/nats/#configuration-file","title":"Configuration File","text":"

        The NATS server can also be configured using a configuration file. To use a configuration file, you need to pass the -c flag to the NATS server:

        nats-server -c <path-to-config-file>\n

        You can find a full reference of the NATS server configuration in the NATS documentation.

        For Telestion, the following settings are of special interest:

        1. websocket - This section configures the WebSocket interface of the NATS server. It\u2019s used by the Telestion frontend to connect to the NATS server.
        2. authorization - This section configures who can publish and subscribe to which subjects.
        3. authorization.users - This section configures the user accounts that can connect to the NATS server. It\u2019s used to configure the user accounts that can connect to the NATS server. As of right now, Telestion exclusively supports username/password-based authentication.
        "},{"location":"Deployment/nats/#development-configuration","title":"Development Configuration","text":"

        The following configuration is a good starting point for development.

        Danger

        Do not use this configuration in production! It\u2019s only meant for development.

        There are several problems with this configuration that make it unsuitable for production:

        1. it doesn\u2019t use TLS for the websocket interface, meaning that all communication is unencrypted
        2. it doesn\u2019t have any authentication or authorization configured, meaning that anyone can connect to the NATS server and publish/subscribe to any subject

        In essence, if you were to use this configuration in production, you would have a NATS server that is publicly accessible and allows anyone with access to your server to publish/subscribe to any subject!

        nats.conf
        http_port: 8222\n\nwebsocket: {\n    port: 9222\n    no_tls: true\n}\n
        "},{"location":"Frontend%20Development/","title":"Frontend","text":"

        Processing data is only half the fun. To make the data accessible to the user, you need a frontend.

        Telestion uses a frontend based on React, TypeScript, and Bootstrap. Thankfully, Telestion (together with vite) provides a lot of tools to make frontend development as easy as possible.

        All you need to get started is an installation of Node.js and pnpm.

        "},{"location":"Frontend%20Development/#creating-a-new-frontend","title":"Creating a new Frontend","text":"

        To create a new frontend, create a new directory for it:

        mkdir telestion-frontend && cd telestion-frontend\n

        Now, add the following files to your directory:

        "},{"location":"Frontend%20Development/#packagejson","title":"package.json","text":"
        {\n  \"name\": \"telestion-frontend\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@wuespace/telestion\": \"^1.0.0-alpha.2\",// (1)!\n    \"react\": \"^18.2.0\",\n    \"zod\": \"^3.22.4\"// (2)!\n  },\n  \"devDependencies\": {\n    \"@vitejs/plugin-react-swc\": \"^3.5.0\",\n    \"vite\": \"^5.0.8\"\n  }\n}\n
        1. Add the @wuespace/telestion package as a dependency. This package contains all the tools you need to get started with frontend development.
        2. Add the zod package as a dependency. This package is used to validate any data that is sent to the frontend.
        "},{"location":"Frontend%20Development/#viteconfigts","title":"vite.config.ts","text":"
        import { defineConfig } from \"vite\";\nimport react from '@vitejs/plugin-react-swc';\n\nexport default defineConfig({\n  plugins: [react()/*(1)!*/],\n});\n
        1. Add the react plugin to vite. This plugin allows you to use React in your frontend.
        "},{"location":"Frontend%20Development/#indexhtml","title":"index.html","text":"
        <!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Telestion Frontend</title>\n  </head>\n  <body data-bs-theme=\"dark\"><!-- (1)! -->\n    <div id=\"root\"></div><!-- (2)! -->\n    <script type=\"module\" src=\"/index.ts\"></script><!-- (3)! -->\n  </body>\n</html>\n
        1. Add the data-bs-theme attribute to the body tag. This attribute is used to set the default theme of the frontend. You can choose between light and dark.
        2. Add a div tag with the id root. This is where your frontend will be rendered.
        3. Add a script tag that loads the index.ts file. This file is the entry point of your frontend.
        "},{"location":"Frontend%20Development/#indexts","title":"index.ts","text":"
        import { initTelestion, registerWidgets } from \"@wuespace/telestion\"; // (1)!\n\nimport \"@wuespace/telestion/telestion.css\"; // (2)!\n\n// initialize Telestion\nawait initTelestion/* (3)!*/({\n  version: \"1.0.0\",// (4)!\n});\n\n// register your widget in Telestion\n// registerWidgets(...);// (5)! \n
        1. Import the initTelestion and registerWidgets functions from the @wuespace/telestion package.
        2. Import the telestion.css file from the @wuespace/telestion package. This file contains all the styles (including all Bootstrap styles) you need to get started with frontend development.
        3. Initialize Telestion. This sets up a basic frontend including authentication, dashboards, etc.
        4. Set the version of your frontend. This is used to check if the user data needs to be migrated.
        5. Register your widgets in Telestion. This is explained in more detail in the next section.
        "},{"location":"Frontend%20Development/#installing-dependencies","title":"Installing Dependencies","text":"

        To install the dependencies, run the following command:

        pnpm install\n
        "},{"location":"Frontend%20Development/#running-the-frontend","title":"Running the Frontend","text":"

        To run the frontend, run the following command:

        pnpm dlx vite\n

        This will start a development server on port 5173. You can now open your browser and navigate to http://localhost:5173.

        "},{"location":"Frontend%20Development/#building-the-frontend","title":"Building the Frontend","text":"

        To build the frontend, run the following command:

        pnpm dlx vite build\n
        "},{"location":"Frontend%20Development/#next-steps","title":"Next Steps","text":"

        Now that you have a basic frontend running, you should have a look at how to add widgets to it.

        "},{"location":"Frontend%20Development/concepts/","title":"Concepts","text":"

        This document describes the various concepts you need to know when building components for the Telestion frontend.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#overview","title":"Overview","text":"

        You can find the most important concepts of the Telestion frontend as well as how they relate to each other in the following diagram:

        graph BT\n  frontend[Telestion Frontend] -->|is written in|react[React]\n  react -->|uses the programming language|ts[TypeScript]\n  user[User] -->|uses|frontend\n  subgraph frontend[Telestion Frontend]\n    dashboard[Dashboard]\n    widgetInstance[Widget Instances]\n    widget[Widgets]\n  end\n  dashboard[Dashboard] -->|is a layout of|widgetInstance[Widget Instances]\n  widget -->|defines the look and behavior of|widgetInstance[Widget Instances]\n  click widgetInstance \"#widget-instances\" \"Widget Instance\"\n  click widget \"#widget\" \"Widget\"\n  click dashboard \"#dashboard\" \"Dashboard\"\n  click react \"#react\" \"React\"\n  click ts \"#typescript\" \"TypeScript\"

        You can click on the elements in the diagram to learn more about them.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#frontend","title":"Frontend","text":"

        The Telestion frontend is the part of Telestion that is visible to the user. It is built with React and TypeScript. It is responsible for displaying data from the backend and for sending commands to the backend.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#dashboard","title":"Dashboard","text":"

        A dashboard is a layout of widget instances with a specific configuration, created by the user. They are the main part of the Telestion frontend.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#widget-instances","title":"Widget Instances","text":"

        A widget instance is an instance of a widget with a specific configuration. They are the building blocks of dashboards.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#widget","title":"Widget","text":"

        A widget is the type of a widget instance. It contains the code that defines how the widget instance looks like and how it behaves.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#htmlcssjavascript","title":"HTML/CSS/JavaScript","text":"

        HTML, CSS, and JavaScript are the three core technologies of the web. HTML is used to describe the structure of web pages. CSS is used to describe the presentation of web pages. JavaScript is used to describe the behavior of web pages.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#react","title":"React","text":"

        The Telestion frontend is built with React. React is a JavaScript library for building user interfaces. It is component-based and declarative. This means that you can build your UI from small, reusable components and that you can describe how your UI should look like without having to worry about how it is rendered.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#components","title":"Components","text":"

        Components are the building blocks of React applications. They are small, reusable pieces of code that can be composed to build more complex components. Components can be either functional or class-based. Functional components are just functions that return a React element.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#jsx","title":"JSX","text":"

        JSX is a syntax extension to JavaScript that allows you to write HTML-like code in your JavaScript files. It is not required to use JSX when writing React applications, but it is recommended. JSX makes your code more readable and easier to write. It also allows you to use the full power of JavaScript inside your HTML-like code.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#props","title":"Props","text":"

        Props are the way to pass data from a parent component to a child component. They are immutable and can only be changed by the parent component. Props are passed to a component as attributes in JSX.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#state","title":"State","text":"

        State is the way to store data inside a component. It is mutable and can be changed by the component itself.

        You can initialize and use state using the useState() hook like this:

        const [counter, setCounter] = useState(0); // initialize with 0\nsetCounter(counter + 1); // increase counter by 1\n
        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#hooks","title":"Hooks","text":"

        Hooks are a new feature that was introduced in React 16.8. They allow you to use state and other React features without writing a class. Hooks are functions that can be called inside functional components. They allow you to use state and other React features without writing a class.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/concepts/#typescript","title":"TypeScript","text":"

        The Telestion frontend is written in TypeScript. TypeScript is a superset of JavaScript that adds static typing to the language. It is a strict superset of JavaScript, which means that any valid JavaScript code is also valid TypeScript code. TypeScript is a statically typed language, which means that the type of a variable is known at compile time. This allows the compiler to catch many errors at compile time instead of at runtime.

        ","tags":["Frontend Development"]},{"location":"Frontend%20Development/api/","title":"Index","text":""},{"location":"Frontend%20Development/api/#modules","title":"Modules","text":"
        • application
        • auth
        • index
        • nats
        • user-data
        • utils
        • widget
        "},{"location":"Frontend%20Development/api/application/","title":"Index","text":"

        @wuespace/telestion / application

        This package provides the main entry point for the Telestion frontend application.

        You can initialize the application by calling the initTelestion function.

        "},{"location":"Frontend%20Development/api/application/#example","title":"Example","text":"
        import { initTelestion } from '@wuespace/telestion/application';\n// or, for convenience:\n// import { initTelestion } from '@wuespace/telestion';\n\ninitTelestion({ ... });\n
        "},{"location":"Frontend%20Development/api/application/#functions","title":"Functions","text":"
        • initTelestion
        "},{"location":"Frontend%20Development/api/application/#references","title":"References","text":""},{"location":"Frontend%20Development/api/application/#telestionoptions","title":"TelestionOptions","text":"

        Re-exports TelestionOptions

        "},{"location":"Frontend%20Development/api/application/#usewidgetconfig","title":"useWidgetConfig","text":"

        Re-exports useWidgetConfig

        "},{"location":"Frontend%20Development/api/application/functions/initTelestion/","title":"initTelestion","text":"

        @wuespace/telestion / application / initTelestion

        initTelestion(options): Promise<void>

        Initialize the Telestion application.

        "},{"location":"Frontend%20Development/api/application/functions/initTelestion/#parameters","title":"Parameters","text":"

        \u2022 options: TelestionOptions

        The options for initializing the application.

        "},{"location":"Frontend%20Development/api/application/functions/initTelestion/#returns","title":"Returns","text":"

        Promise<void>

        A Promise that resolves once the initialization is completed.

        "},{"location":"Frontend%20Development/api/auth/","title":"Index","text":"

        @wuespace/telestion / auth

        Functions and types relating to the authentication of users in the Telestion frontend.

        Note that in most cases, you don\u2019t need to import anything from this package directly, since auth*n is already handled by the framework itself.

        "},{"location":"Frontend%20Development/api/auth/#example","title":"Example","text":"
        import { ... } from '@wuespace/telestion/auth';\n
        "},{"location":"Frontend%20Development/api/auth/#classes","title":"Classes","text":"
        • LoginError
        "},{"location":"Frontend%20Development/api/auth/#interfaces","title":"Interfaces","text":"
        • ErrorMessages
        • User
        "},{"location":"Frontend%20Development/api/auth/#functions","title":"Functions","text":"
        • attemptAutoLogin
        • getNatsConnection
        • getUser
        • isLoggedIn
        • login
        • logout
        • setAutoLoginCredentials
        • setNatsConnection
        • setUser
        • useNatsSubscription
        "},{"location":"Frontend%20Development/api/auth/#references","title":"References","text":""},{"location":"Frontend%20Development/api/auth/#usenats","title":"useNats","text":"

        Re-exports useNats

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/","title":"LoginError","text":"

        @wuespace/telestion / auth / LoginError

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#extends","title":"Extends","text":"
        • Error
        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#constructors","title":"Constructors","text":""},{"location":"Frontend%20Development/api/auth/classes/LoginError/#new-loginerrormessages","title":"new LoginError(messages)","text":"

        new LoginError(messages): LoginError

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#parameters","title":"Parameters","text":"

        \u2022 messages: ErrorMessages

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#returns","title":"Returns","text":"

        LoginError

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#overrides","title":"Overrides","text":"

        Error.constructor

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/auth/classes/LoginError/#message","title":"message","text":"

        message: string

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from","title":"Inherited from","text":"

        Error.message

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#messages","title":"messages","text":"

        messages: ErrorMessages

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#name","title":"name","text":"

        name: string

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from_1","title":"Inherited from","text":"

        Error.name

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#stack","title":"stack?","text":"

        stack?: string

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from_2","title":"Inherited from","text":"

        Error.stack

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#preparestacktrace","title":"prepareStackTrace?","text":"

        static prepareStackTrace?: (err, stackTraces) => any

        Optional override for formatting stack traces

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#parameters_1","title":"Parameters","text":"

        \u2022 err: Error

        \u2022 stackTraces: CallSite[]

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#returns_1","title":"Returns","text":"

        any

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#see","title":"See","text":"

        https://v8.dev/docs/stack-trace-api#customizing-stack-traces

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from_3","title":"Inherited from","text":"

        Error.prepareStackTrace

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#stacktracelimit","title":"stackTraceLimit","text":"

        static stackTraceLimit: number

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from_4","title":"Inherited from","text":"

        Error.stackTraceLimit

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/auth/classes/LoginError/#capturestacktrace","title":"captureStackTrace()","text":"

        static captureStackTrace(targetObject, constructorOpt?): void

        Create .stack property on a target object

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#parameters_2","title":"Parameters","text":"

        \u2022 targetObject: object

        \u2022 constructorOpt?: Function

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#returns_2","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/auth/classes/LoginError/#inherited-from_5","title":"Inherited from","text":"

        Error.captureStackTrace

        "},{"location":"Frontend%20Development/api/auth/functions/attemptAutoLogin/","title":"attemptAutoLogin","text":"

        @wuespace/telestion / auth / attemptAutoLogin

        attemptAutoLogin(): Promise<boolean>

        Attempt to auto-login using credentials stored in sessionStorage.

        The credentials will automatically be cleared if they are invalid, the session ends, or logout is called.

        Credentials are automatically stored updated by login and logout.

        "},{"location":"Frontend%20Development/api/auth/functions/attemptAutoLogin/#returns","title":"Returns","text":"

        Promise<boolean>

        true if auto-login was successful, false otherwise

        "},{"location":"Frontend%20Development/api/auth/functions/getNatsConnection/","title":"getNatsConnection","text":"

        @wuespace/telestion / auth / getNatsConnection

        getNatsConnection(): null | NatsConnection

        "},{"location":"Frontend%20Development/api/auth/functions/getNatsConnection/#returns","title":"Returns","text":"

        null | NatsConnection

        "},{"location":"Frontend%20Development/api/auth/functions/getUser/","title":"getUser","text":"

        @wuespace/telestion / auth / getUser

        getUser(): null | User

        Returns the user object if the user is currently logged in, else returns null if no user is currently logged in.

        "},{"location":"Frontend%20Development/api/auth/functions/getUser/#returns","title":"Returns","text":"

        null | User

        "},{"location":"Frontend%20Development/api/auth/functions/isLoggedIn/","title":"isLoggedIn","text":"

        @wuespace/telestion / auth / isLoggedIn

        isLoggedIn(): boolean

        Checks if a user is logged in.

        "},{"location":"Frontend%20Development/api/auth/functions/isLoggedIn/#returns","title":"Returns","text":"

        boolean

        true if the user is logged in, false otherwise.

        "},{"location":"Frontend%20Development/api/auth/functions/login/","title":"Login","text":"

        @wuespace/telestion / auth / login

        login(natsUrl, username, password): Promise<null | User>

        Logs in a user with the given credentials.

        "},{"location":"Frontend%20Development/api/auth/functions/login/#parameters","title":"Parameters","text":"

        \u2022 natsUrl: string

        The url to connect to the NATS server.

        \u2022 username: string

        The username for authentication.

        \u2022 password: string

        The password for authentication.

        "},{"location":"Frontend%20Development/api/auth/functions/login/#returns","title":"Returns","text":"

        Promise<null | User>

        A promise that resolves once the user is logged in. The resolved value is the logged-in user object.

        "},{"location":"Frontend%20Development/api/auth/functions/login/#throws","title":"Throws","text":"

        Error If the provided credentials are incorrect.

        "},{"location":"Frontend%20Development/api/auth/functions/logout/","title":"Logout","text":"

        @wuespace/telestion / auth / logout

        logout(): Promise<void>

        Logs out the user if currently logged in.

        "},{"location":"Frontend%20Development/api/auth/functions/logout/#returns","title":"Returns","text":"

        Promise<void>

        A promise that resolves once the user is logged out.

        "},{"location":"Frontend%20Development/api/auth/functions/setAutoLoginCredentials/","title":"setAutoLoginCredentials","text":"

        @wuespace/telestion / auth / setAutoLoginCredentials

        setAutoLoginCredentials(credentials): void

        Sets credentials with which to auto-login.

        If an auto-login attempt fails, the credentials will be cleared for the remainder of the session and a login form shown to the user. If the user logs in successfully, the credentials will be updated.

        "},{"location":"Frontend%20Development/api/auth/functions/setAutoLoginCredentials/#security-warning","title":"Security Warning","text":"

        Use this function only if user authentication is handled by a separate system. Calling this function in your application means your NATS credentials will be hard-coded into your application, which is a security risk.

        "},{"location":"Frontend%20Development/api/auth/functions/setAutoLoginCredentials/#parameters","title":"Parameters","text":"

        \u2022 credentials: Object

        The credentials to store

        \u2022 credentials.natsUrl: string= undefined

        The URL of the NATS server to connect to.

        \u2022 credentials.password: string= undefined

        The password to use when connecting to the NATS server.

        \u2022 credentials.username: string= undefined

        The username to use when connecting to the NATS server.

        "},{"location":"Frontend%20Development/api/auth/functions/setAutoLoginCredentials/#returns","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/auth/functions/setAutoLoginCredentials/#deprecated","title":"Deprecated","text":"

        No, this won\u2019t be removed anytime soon. You can ignore this warning if you\u2019re aware of the security implications.

        "},{"location":"Frontend%20Development/api/auth/functions/setNatsConnection/","title":"setNatsConnection","text":"

        @wuespace/telestion / auth / setNatsConnection

        setNatsConnection(nc): void

        "},{"location":"Frontend%20Development/api/auth/functions/setNatsConnection/#parameters","title":"Parameters","text":"

        \u2022 nc: null | NatsConnection

        "},{"location":"Frontend%20Development/api/auth/functions/setNatsConnection/#returns","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/auth/functions/setUser/","title":"setUser","text":"

        @wuespace/telestion / auth / setUser

        setUser(user): void

        Sets a new user object or null if the user is no longer logged in.

        "},{"location":"Frontend%20Development/api/auth/functions/setUser/#parameters","title":"Parameters","text":"

        \u2022 user: null | User

        the user object or null

        "},{"location":"Frontend%20Development/api/auth/functions/setUser/#returns","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/auth/functions/useNatsSubscription/","title":"useNatsSubscription","text":"

        @wuespace/telestion / auth / useNatsSubscription

        useNatsSubscription(subject, callback, options?): void

        "},{"location":"Frontend%20Development/api/auth/functions/useNatsSubscription/#parameters","title":"Parameters","text":"

        \u2022 subject: string

        \u2022 callback: (message) => void | Promise<void>

        \u2022 options?: SubscriptionOptions

        "},{"location":"Frontend%20Development/api/auth/functions/useNatsSubscription/#returns","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/auth/interfaces/ErrorMessages/","title":"ErrorMessages","text":"

        @wuespace/telestion / auth / ErrorMessages

        "},{"location":"Frontend%20Development/api/auth/interfaces/ErrorMessages/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/auth/interfaces/ErrorMessages/#natsurlmessage","title":"natsUrlMessage?","text":"

        natsUrlMessage?: string

        "},{"location":"Frontend%20Development/api/auth/interfaces/ErrorMessages/#passwordmessage","title":"passwordMessage?","text":"

        passwordMessage?: string

        "},{"location":"Frontend%20Development/api/auth/interfaces/ErrorMessages/#usernamemessage","title":"usernameMessage?","text":"

        usernameMessage?: string

        "},{"location":"Frontend%20Development/api/auth/interfaces/User/","title":"User","text":"

        @wuespace/telestion / auth / User

        A logged-in user.

        "},{"location":"Frontend%20Development/api/auth/interfaces/User/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/auth/interfaces/User/#natsurl","title":"natsUrl","text":"

        natsUrl: string

        The NATS URL that the user is connected to.

        "},{"location":"Frontend%20Development/api/auth/interfaces/User/#username","title":"username","text":"

        username: string

        The user\u2019s username.

        "},{"location":"Frontend%20Development/api/index/","title":"Index","text":"

        @wuespace/telestion / index

        The Telestion Frontend Library.

        Import this library to use the Telestion Frontend:

        import { initTelestion } from '@wuespace/telestion';\n

        The most important function is initTelestion. It initializes the Telestion Frontend and renders the application.

        initTelestion({\n  version: '1.0.0',\n  ...\n});\n
        "},{"location":"Frontend%20Development/api/index/#see","title":"See","text":"

        initTelestion

        "},{"location":"Frontend%20Development/api/index/#interfaces","title":"Interfaces","text":"
        • TelestionOptions
        • Widget
        "},{"location":"Frontend%20Development/api/index/#type-aliases","title":"Type Aliases","text":"
        • UserData
        "},{"location":"Frontend%20Development/api/index/#functions","title":"Functions","text":"
        • JSONCodec
        • registerWidgets
        • useNats
        • useWidgetConfig
        "},{"location":"Frontend%20Development/api/index/#references","title":"References","text":""},{"location":"Frontend%20Development/api/index/#inittelestion","title":"initTelestion","text":"

        Re-exports initTelestion

        "},{"location":"Frontend%20Development/api/index/functions/JSONCodec/","title":"JSONCodec","text":"

        @wuespace/telestion / index / JSONCodec

        JSONCodec<T>(reviver?): Codec<T>

        Returns a Codec for encoding JavaScript object to JSON and serialize them to an Uint8Array, and conversely, from an Uint8Array to JSON to a JavaScript Object.

        "},{"location":"Frontend%20Development/api/index/functions/JSONCodec/#type-parameters","title":"Type parameters","text":"

        \u2022 T = unknown

        "},{"location":"Frontend%20Development/api/index/functions/JSONCodec/#parameters","title":"Parameters","text":"

        \u2022 reviver?: (this, key, value) => unknown

        "},{"location":"Frontend%20Development/api/index/functions/JSONCodec/#returns","title":"Returns","text":"

        Codec<T>

        "},{"location":"Frontend%20Development/api/index/functions/registerWidgets/","title":"registerWidgets","text":"

        @wuespace/telestion / index / registerWidgets

        registerWidgets(\u2026widgets): void

        Registers widgets in the widget store.

        If a widget with the same ID already exists in the widget store, a warning is logged and the widget is ignored.

        "},{"location":"Frontend%20Development/api/index/functions/registerWidgets/#parameters","title":"Parameters","text":"

        \u2022 \u2026widgets: Widget<Record<string, unknown>>[]

        The widgets to be registered.

        "},{"location":"Frontend%20Development/api/index/functions/registerWidgets/#returns","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/index/functions/useNats/","title":"useNats","text":"

        @wuespace/telestion / index / useNats

        useNats(): NatsConnection

        "},{"location":"Frontend%20Development/api/index/functions/useNats/#returns","title":"Returns","text":"

        NatsConnection

        "},{"location":"Frontend%20Development/api/index/functions/useWidgetConfig/","title":"useWidgetConfig","text":"

        @wuespace/telestion / index / useWidgetConfig

        useWidgetConfig<T>(): T

        Retrieves the widget configuration from the widgetConfigContext.

        "},{"location":"Frontend%20Development/api/index/functions/useWidgetConfig/#type-parameters","title":"Type parameters","text":"

        \u2022 T

        The type of the widget configuration.

        "},{"location":"Frontend%20Development/api/index/functions/useWidgetConfig/#returns","title":"Returns","text":"

        T

        The widget configuration retrieved from the widgetConfigContext.

        "},{"location":"Frontend%20Development/api/index/functions/useWidgetConfig/#throws","title":"Throws","text":"

        Error Throws an error if useWidgetConfig is not used within a WidgetConfigProvider.

        "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/","title":"TelestionOptions","text":"

        @wuespace/telestion / index / TelestionOptions

        Represents the options for Telestion.

        "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#defaultbackendurl","title":"defaultBackendUrl?","text":"

        defaultBackendUrl?: string

        The backend URL that should be inserted by default on first page load.

        "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#defaultuserdata","title":"defaultUserData?","text":"

        defaultUserData?: Object

        Represents the default user data.

        "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#type-declaration","title":"Type declaration","text":""},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#dashboards","title":"dashboards","text":"

        dashboards: Record<string, { title: string; layout: string[][]; }>

        The user\u2019s dashboards.

        "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#version","title":"version","text":"

        version: string

        The version of the client that created this user data.

        "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#widgetinstances","title":"widgetInstances","text":"

        widgetInstances: Record<string, { type: string; configuration: Record<string, unknown>; }>

        The user\u2019s widget instances.

        "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#version_1","title":"version","text":"

        version: string

        Represents the current version of the software.

        "},{"location":"Frontend%20Development/api/index/interfaces/TelestionOptions/#widgets","title":"widgets?","text":"

        widgets?: Widget<Record<string, unknown>>[]

        Represents an array of widgets.

        "},{"location":"Frontend%20Development/api/index/interfaces/Widget/","title":"Widget","text":"

        @wuespace/telestion / index / Widget

        A widget that can be used in widget instances on dashboards.

        "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#see","title":"See","text":"

        userData.WidgetInstance

        "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#type-parameters","title":"Type parameters","text":"

        \u2022 T extends Record<string, unknown> = Record<string, unknown>

        the type of the widget configuration

        "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/index/interfaces/Widget/#configelement","title":"configElement","text":"

        configElement: ReactNode

        A configuration element that is used to configure the widget.

        "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#element","title":"element","text":"

        element: ReactNode

        A function that takes the configuration of the widget and returns a React element that represents the widget.

        "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#id","title":"id","text":"

        id: string

        Represents an identifier of the widget type.

        "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#label","title":"label","text":"

        label: string

        Represents a human-readable label of the widget type.

        "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/index/interfaces/Widget/#createconfig","title":"createConfig()","text":"

        createConfig(input): T

        A function that takes an object that contains the previous widget configuration (which may or may not be from a previous version of the client (or could also, when creating new widget instances, be empty) and returns a valid configuration for the widget.

        For widgets with expected breaking changes, it is therefore useful to have some version identifier be a part of the configuration options to enable more complex migration logic in this function.

        "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#parameters","title":"Parameters","text":"

        \u2022 input: Partial<T> & Record<string, unknown>

        previous configuration or empty

        "},{"location":"Frontend%20Development/api/index/interfaces/Widget/#returns","title":"Returns","text":"

        T

        "},{"location":"Frontend%20Development/api/index/type-aliases/UserData/","title":"UserData","text":"

        @wuespace/telestion / index / UserData

        UserData: Object

        Represents the user data.

        "},{"location":"Frontend%20Development/api/index/type-aliases/UserData/#see","title":"See","text":"

        userDataSchema

        "},{"location":"Frontend%20Development/api/index/type-aliases/UserData/#type-declaration","title":"Type declaration","text":""},{"location":"Frontend%20Development/api/index/type-aliases/UserData/#dashboards","title":"dashboards","text":"

        dashboards: Record<string, { title: string; layout: string[][]; }>

        The user\u2019s dashboards.

        "},{"location":"Frontend%20Development/api/index/type-aliases/UserData/#version","title":"version","text":"

        version: string

        The version of the client that created this user data.

        "},{"location":"Frontend%20Development/api/index/type-aliases/UserData/#widgetinstances","title":"widgetInstances","text":"

        widgetInstances: Record<string, { type: string; configuration: Record<string, unknown>; }>

        The user\u2019s widget instances.

        "},{"location":"Frontend%20Development/api/nats/","title":"Index","text":"

        @wuespace/telestion / nats

        Re-exporting the most used types and functions from the nats.ws package.

        "},{"location":"Frontend%20Development/api/nats/#example","title":"Example","text":"
        import { Msg, JSONCodec, ... } from '@wuespace/telestion/nats';\n
        "},{"location":"Frontend%20Development/api/nats/#see","title":"See","text":"
        • https://docs.nats.io/using-nats/developer
        • https://github.com/nats-io/nats.ws#readme
        "},{"location":"Frontend%20Development/api/nats/#classes","title":"Classes","text":"
        • NatsError
        "},{"location":"Frontend%20Development/api/nats/#interfaces","title":"Interfaces","text":"
        • Codec
        • Msg
        • MsgHdrs
        • NatsConnection
        • PublishOptions
        • RequestOptions
        • Sub
        • SubOpts
        "},{"location":"Frontend%20Development/api/nats/#type-aliases","title":"Type Aliases","text":"
        • MsgRequest
        • Subscription
        • SubscriptionOptions
        "},{"location":"Frontend%20Development/api/nats/#functions","title":"Functions","text":"
        • StringCodec
        • headers
        "},{"location":"Frontend%20Development/api/nats/#references","title":"References","text":""},{"location":"Frontend%20Development/api/nats/#jsoncodec","title":"JSONCodec","text":"

        Re-exports JSONCodec

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/","title":"NatsError","text":"

        @wuespace/telestion / nats / NatsError

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#extends","title":"Extends","text":"
        • Error
        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#constructors","title":"Constructors","text":""},{"location":"Frontend%20Development/api/nats/classes/NatsError/#new-natserrormessage-code-chainederror","title":"new NatsError(message, code, chainedError)","text":"

        new NatsError(message, code, chainedError?): NatsError

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#parameters","title":"Parameters","text":"

        \u2022 message: string

        \u2022 code: string

        \u2022 chainedError?: Error

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns","title":"Returns","text":"

        NatsError

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#overrides","title":"Overrides","text":"

        Error.constructor

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#api","title":"Api","text":"

        private

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/classes/NatsError/#api_error","title":"api_error?","text":"

        api_error?: ApiError

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#chainederror","title":"chainedError?","text":"

        chainedError?: Error

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#code","title":"code","text":"

        code: string

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#message","title":"message","text":"

        message: string

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#overrides_1","title":"Overrides","text":"

        Error.message

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#name","title":"name","text":"

        name: string

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#overrides_2","title":"Overrides","text":"

        Error.name

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#permissioncontext","title":"permissionContext?","text":"

        permissionContext?: Object

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#type-declaration","title":"Type declaration","text":""},{"location":"Frontend%20Development/api/nats/classes/NatsError/#operation","title":"operation","text":"

        operation: string

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#subject","title":"subject","text":"

        subject: string

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#stack","title":"stack?","text":"

        stack?: string

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#inherited-from","title":"Inherited from","text":"

        Error.stack

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#preparestacktrace","title":"prepareStackTrace?","text":"

        static prepareStackTrace?: (err, stackTraces) => any

        Optional override for formatting stack traces

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#parameters_1","title":"Parameters","text":"

        \u2022 err: Error

        \u2022 stackTraces: CallSite[]

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_1","title":"Returns","text":"

        any

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#see","title":"See","text":"

        https://v8.dev/docs/stack-trace-api#customizing-stack-traces

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#inherited-from_1","title":"Inherited from","text":"

        Error.prepareStackTrace

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#stacktracelimit","title":"stackTraceLimit","text":"

        static stackTraceLimit: number

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#inherited-from_2","title":"Inherited from","text":"

        Error.stackTraceLimit

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/classes/NatsError/#isautherror","title":"isAuthError()","text":"

        isAuthError(): boolean

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_2","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#isauthtimeout","title":"isAuthTimeout()","text":"

        isAuthTimeout(): boolean

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_3","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#isjetstreamerror","title":"isJetStreamError()","text":"

        isJetStreamError(): boolean

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_4","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#ispermissionerror","title":"isPermissionError()","text":"

        isPermissionError(): boolean

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_5","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#isprotocolerror","title":"isProtocolError()","text":"

        isProtocolError(): boolean

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_6","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#jserror","title":"jsError()","text":"

        jsError(): null | ApiError

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_7","title":"Returns","text":"

        null | ApiError

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#capturestacktrace","title":"captureStackTrace()","text":"

        static captureStackTrace(targetObject, constructorOpt?): void

        Create .stack property on a target object

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#parameters_2","title":"Parameters","text":"

        \u2022 targetObject: object

        \u2022 constructorOpt?: Function

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_8","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#inherited-from_3","title":"Inherited from","text":"

        Error.captureStackTrace

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#errorforcode","title":"errorForCode()","text":"

        static errorForCode(code, chainedError?): NatsError

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#parameters_3","title":"Parameters","text":"

        \u2022 code: string

        \u2022 chainedError?: Error

        "},{"location":"Frontend%20Development/api/nats/classes/NatsError/#returns_9","title":"Returns","text":"

        NatsError

        "},{"location":"Frontend%20Development/api/nats/functions/StringCodec/","title":"StringCodec","text":"

        @wuespace/telestion / nats / StringCodec

        StringCodec(): Codec<string>

        Returns a Codec for encoding strings to a message payload and decoding message payloads into strings.

        "},{"location":"Frontend%20Development/api/nats/functions/StringCodec/#returns","title":"Returns","text":"

        Codec<string>

        "},{"location":"Frontend%20Development/api/nats/functions/headers/","title":"Headers","text":"

        @wuespace/telestion / nats / headers

        headers(code?, description?): MsgHdrs

        "},{"location":"Frontend%20Development/api/nats/functions/headers/#parameters","title":"Parameters","text":"

        \u2022 code?: number

        \u2022 description?: string

        "},{"location":"Frontend%20Development/api/nats/functions/headers/#returns","title":"Returns","text":"

        MsgHdrs

        "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/","title":"Codec","text":"

        @wuespace/telestion / nats / Codec

        "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#type-parameters","title":"Type parameters","text":"

        \u2022 T

        "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#decode","title":"decode()","text":"

        decode(a): T

        Decode an Uint8Array from a message payload into a T

        "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#parameters","title":"Parameters","text":"

        \u2022 a: Uint8Array

        "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#returns","title":"Returns","text":"

        T

        "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#encode","title":"encode()","text":"

        encode(d): Uint8Array

        Encode T to an Uint8Array suitable for including in a message payload.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#parameters_1","title":"Parameters","text":"

        \u2022 d: T

        "},{"location":"Frontend%20Development/api/nats/interfaces/Codec/#returns_1","title":"Returns","text":"

        Uint8Array

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/","title":"Msg","text":"

        @wuespace/telestion / nats / Msg

        Represents a message delivered by NATS. This interface is used by Subscribers.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#data","title":"data","text":"

        data: Uint8Array

        The message\u2019s data (or payload)

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#headers","title":"headers?","text":"

        headers?: MsgHdrs

        Possible headers that may have been set by the server or the publisher.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#reply","title":"reply?","text":"

        reply?: string

        A possible subject where the recipient may publish a reply (in the cases where the message represents a request).

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#sid","title":"sid","text":"

        sid: number

        The subscription ID where the message was dispatched.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#subject","title":"subject","text":"

        subject: string

        The subject the message was sent to

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#json","title":"json()","text":"

        json<T>(reviver?): T

        Convenience method to parse the message payload as JSON. This method will throw an exception if there\u2019s a parsing error;

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#type-parameters","title":"Type parameters","text":"

        \u2022 T

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#parameters","title":"Parameters","text":"

        \u2022 reviver?: ReviverFn

        a reviver function

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#returns","title":"Returns","text":"

        T

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#respond","title":"respond()","text":"

        respond(payload?, opts?): boolean

        Convenience to publish a response to the reply subject in the message - this is the same as doing nc.publish(msg.reply, ...).

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#parameters_1","title":"Parameters","text":"

        \u2022 payload?: Payload

        \u2022 opts?: PublishOptions

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#returns_1","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#string","title":"string()","text":"

        string(): string

        Convenience method to parse the message payload as string. This method may throw an exception if there\u2019s a conversion error

        "},{"location":"Frontend%20Development/api/nats/interfaces/Msg/#returns_2","title":"Returns","text":"

        string

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/","title":"MsgHdrs","text":"

        @wuespace/telestion / nats / MsgHdrs

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#extends","title":"Extends","text":"
        • Iterable<[string, string[]]>
        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#code","title":"code","text":"

        code: number

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#description","title":"description","text":"

        description: string

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#haserror","title":"hasError","text":"

        hasError: boolean

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#status","title":"status","text":"

        status: string

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#iterator","title":"[iterator]()","text":"

        [iterator](): Iterator<[string, string[]], any, undefined>

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns","title":"Returns","text":"

        Iterator<[string, string[]], any, undefined>

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#inherited-from","title":"Inherited from","text":"

        Iterable.[iterator]

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#append","title":"append()","text":"

        append(k, v, match?): void

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters","title":"Parameters","text":"

        \u2022 k: string

        \u2022 v: string

        \u2022 match?: Match

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_1","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#delete","title":"delete()","text":"

        delete(k, match?): void

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_1","title":"Parameters","text":"

        \u2022 k: string

        \u2022 match?: Match

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_2","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#get","title":"get()","text":"

        get(k, match?): string

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_2","title":"Parameters","text":"

        \u2022 k: string

        \u2022 match?: Match

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_3","title":"Returns","text":"

        string

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#has","title":"has()","text":"

        has(k, match?): boolean

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_3","title":"Parameters","text":"

        \u2022 k: string

        \u2022 match?: Match

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_4","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#keys","title":"keys()","text":"

        keys(): string[]

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_5","title":"Returns","text":"

        string[]

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#last","title":"last()","text":"

        last(k, match?): string

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_4","title":"Parameters","text":"

        \u2022 k: string

        \u2022 match?: Match

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_6","title":"Returns","text":"

        string

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#set","title":"set()","text":"

        set(k, v, match?): void

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_5","title":"Parameters","text":"

        \u2022 k: string

        \u2022 v: string

        \u2022 match?: Match

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_7","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#values","title":"values()","text":"

        values(k, match?): string[]

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#parameters_6","title":"Parameters","text":"

        \u2022 k: string

        \u2022 match?: Match

        "},{"location":"Frontend%20Development/api/nats/interfaces/MsgHdrs/#returns_8","title":"Returns","text":"

        string[]

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/","title":"NatsConnection","text":"

        @wuespace/telestion / nats / NatsConnection

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#info","title":"info?","text":"

        info?: ServerInfo

        ServerInfo to the currently connected server or undefined

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#services","title":"services","text":"

        services: ServicesAPI

        Returns a ServicesAPI which allows you to build services using NATS.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#close","title":"close()","text":"

        close(): Promise<void>

        Close will close the connection to the server. This call will terminate all pending requests and subscriptions. The returned promise resolves when the connection closes.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns","title":"Returns","text":"

        Promise<void>

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#closed","title":"closed()","text":"

        closed(): Promise<void | Error>

        Returns a promise that can be used to monitor if the client closes. The promise can resolve an Error if the reason for the close was an error. Note that the promise doesn\u2019t reject, but rather resolves to the error if there was one.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_1","title":"Returns","text":"

        Promise<void | Error>

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#drain","title":"drain()","text":"

        drain(): Promise<void>

        Initiates a drain on the connection and returns a promise that resolves when the drain completes and the connection closes.

        Drain is an ordered shutdown of the client. Instead of abruptly closing the client, subscriptions are drained, that is messages not yet processed by a subscription are handled before the subscription is closed. After subscriptions are drained it is not possible to create a new subscription. Then all pending outbound messages are sent to the server. Finally, the connection is closed.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_2","title":"Returns","text":"

        Promise<void>

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#flush","title":"flush()","text":"

        flush(): Promise<void>

        Returns a Promise that resolves when the client receives a reply from the server. Use of this API is not necessary by clients.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_3","title":"Returns","text":"

        Promise<void>

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#getserver","title":"getServer()","text":"

        getServer(): string

        Returns the hostport of the server the client is connected to.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_4","title":"Returns","text":"

        string

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#isclosed","title":"isClosed()","text":"

        isClosed(): boolean

        Returns true if the client is closed.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_5","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#isdraining","title":"isDraining()","text":"

        isDraining(): boolean

        Returns true if the client is draining.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_6","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#jetstream","title":"jetstream()","text":"

        jetstream(opts?): JetStreamClient

        Returns a JetStreamClient which allows publishing messages to JetStream or consuming messages from streams.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters","title":"Parameters","text":"

        \u2022 opts?: JetStreamOptions

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_7","title":"Returns","text":"

        JetStreamClient

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#jetstreammanager","title":"jetstreamManager()","text":"

        jetstreamManager(opts?): Promise<JetStreamManager>

        Returns a Promise to a JetStreamManager which allows the client to access Streams and Consumers information.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters_1","title":"Parameters","text":"

        \u2022 opts?: JetStreamManagerOptions

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_8","title":"Returns","text":"

        Promise<JetStreamManager>

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#publish","title":"publish()","text":"

        publish(subject, payload?, options?): void

        Publishes the specified data to the specified subject.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters_2","title":"Parameters","text":"

        \u2022 subject: string

        \u2022 payload?: Payload

        \u2022 options?: PublishOptions

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_9","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#reconnect","title":"reconnect()","text":"

        reconnect(): Promise<void>

        Use of this API is experimental, and it is subject to be removed.

        reconnect() enables a client to force a reconnect. A reconnect will disconnect the client, and possibly initiate a reconnect to the cluster. Note that all reconnect caveats apply:

        • If the reconnection policy given to the client doesn\u2019t allow reconnects, the connection will close.

        • Messages that are inbound or outbound could be lost.

        • All requests that are in flight will be rejected.

        Note that the returned promise will reject if the client is already closed, or if it is in the process of draining. If the client is currently disconnected, this API has no effect, as the client is already attempting to reconnect.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_10","title":"Returns","text":"

        Promise<void>

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#request","title":"request()","text":"

        request(subject, payload?, opts?): Promise<Msg>

        Publishes a request with specified data in the specified subject expecting a response before RequestOptions#timeout milliseconds. The api returns a Promise that resolves when the first response to the request is received. If there are no responders (a subscription) listening on the request subject, the request will fail as soon as the server processes it.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters_3","title":"Parameters","text":"

        \u2022 subject: string

        \u2022 payload?: Payload

        \u2022 opts?: RequestOptions

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_11","title":"Returns","text":"

        Promise<Msg>

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#requestmany","title":"requestMany()","text":"

        requestMany(subject, payload?, opts?): Promise<AsyncIterable<Msg>>

        Publishes a request expecting multiple responses back. Several strategies to determine when the request should stop gathering responses.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters_4","title":"Parameters","text":"

        \u2022 subject: string

        \u2022 payload?: Payload

        \u2022 opts?: Partial<RequestManyOptions>

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_12","title":"Returns","text":"

        Promise<AsyncIterable<Msg>>

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#rtt","title":"rtt()","text":"

        rtt(): Promise<number>

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_13","title":"Returns","text":"

        Promise<number>

        the number of milliseconds it took for a flush.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#stats","title":"stats()","text":"

        stats(): Stats

        Returns some metrics such as the number of messages and bytes sent and recieved by the client.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_14","title":"Returns","text":"

        Stats

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#status","title":"status()","text":"

        status(): AsyncIterable<Status>

        Returns an async iterator of Status that may be useful in understanding when the client looses a connection, or reconnects, or receives an update from the cluster among other things.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_15","title":"Returns","text":"

        AsyncIterable<Status>

        an AsyncIterable"},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#subscribe","title":"subscribe()","text":"

        subscribe(subject, opts?): Subscription

        Subscribe expresses interest in the specified subject. The subject may have wildcards. Messages are delivered to the SubscriptionOptions callback if specified. Otherwise, the subscription is an async iterator for Msg.

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#parameters_5","title":"Parameters","text":"

        \u2022 subject: string

        \u2022 opts?: SubscriptionOptions

        "},{"location":"Frontend%20Development/api/nats/interfaces/NatsConnection/#returns_16","title":"Returns","text":"

        Subscription

        "},{"location":"Frontend%20Development/api/nats/interfaces/PublishOptions/","title":"PublishOptions","text":"

        @wuespace/telestion / nats / PublishOptions

        "},{"location":"Frontend%20Development/api/nats/interfaces/PublishOptions/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/PublishOptions/#headers","title":"headers?","text":"

        headers?: MsgHdrs

        Optional headers to include with the message.

        "},{"location":"Frontend%20Development/api/nats/interfaces/PublishOptions/#reply","title":"reply?","text":"

        reply?: string

        An optional subject where a response should be sent. Note you must have a subscription listening on this subject to receive the response.

        "},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/","title":"RequestOptions","text":"

        @wuespace/telestion / nats / RequestOptions

        "},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/#headers","title":"headers?","text":"

        headers?: MsgHdrs

        MsgHdrs to include with the request.

        "},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/#nomux","title":"noMux?","text":"

        noMux?: boolean

        If true, the request API will create a regular NATS subscription to process the response. Otherwise a shared muxed subscriptions is used. Requires reply

        "},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/#reply","title":"reply?","text":"

        reply?: string

        The subject where the response should be sent to. Requires noMux

        "},{"location":"Frontend%20Development/api/nats/interfaces/RequestOptions/#timeout","title":"timeout","text":"

        timeout: number

        number of milliseconds before the request will timeout.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/","title":"Sub","text":"

        @wuespace/telestion / nats / Sub

        Basic interface to a Subscription type

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#extends","title":"Extends","text":"
        • AsyncIterable<T>
        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#type-parameters","title":"Type parameters","text":"

        \u2022 T

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#closed","title":"closed","text":"

        closed: Promise<void>

        A promise that resolves when the subscription closes

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#methods","title":"Methods","text":""},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#asynciterator","title":"[asyncIterator]()","text":"

        [asyncIterator](): AsyncIterator<T, any, undefined>

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns","title":"Returns","text":"

        AsyncIterator<T, any, undefined>

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#inherited-from","title":"Inherited from","text":"

        AsyncIterable.[asyncIterator]

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#drain","title":"drain()","text":"

        drain(): Promise<void>

        Drain the subscription, closing it after processing all messages currently in flight for the client. Returns a promise that resolves when the subscription finished draining.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_1","title":"Returns","text":"

        Promise<void>

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#getmax","title":"getMax()","text":"

        getMax(): undefined | number

        Return the max number of messages before the subscription will unsubscribe.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_2","title":"Returns","text":"

        undefined | number

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#getpending","title":"getPending()","text":"

        getPending(): number

        Returns the number of messages that are pending processing. Note that this is method is only valid for iterators.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_3","title":"Returns","text":"

        number

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#getprocessed","title":"getProcessed()","text":"

        getProcessed(): number

        Returns the number of messages that have been processed by the subscription.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_4","title":"Returns","text":"

        number

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#getreceived","title":"getReceived()","text":"

        getReceived(): number

        Returns the number of messages received by the subscription.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_5","title":"Returns","text":"

        number

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#getsubject","title":"getSubject()","text":"

        getSubject(): string

        Returns the subject that was used to create the subscription.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_6","title":"Returns","text":"

        string

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#isclosed","title":"isClosed()","text":"

        isClosed(): boolean

        Returns true if the subscription is closed.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_7","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#isdraining","title":"isDraining()","text":"

        isDraining(): boolean

        Returns true if the subscription is draining.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_8","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#unsubscribe","title":"unsubscribe()","text":"

        unsubscribe(max?): void

        Stop the subscription from receiving messages. You can optionally specify that the subscription should stop after the specified number of messages have been received. Note this count is since the lifetime of the subscription.

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#parameters","title":"Parameters","text":"

        \u2022 max?: number

        "},{"location":"Frontend%20Development/api/nats/interfaces/Sub/#returns_9","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/","title":"SubOpts","text":"

        @wuespace/telestion / nats / SubOpts

        Subscription Options

        "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#type-parameters","title":"Type parameters","text":"

        \u2022 T

        "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#callback","title":"callback?","text":"

        callback?: (err, msg) => void

        An optional function that will handle messages. Typically, messages are processed via an async iterator on the subscription. If this option is provided, messages are processed by the specified function.

        "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#parameters","title":"Parameters","text":"

        \u2022 err: null | NatsError

        \u2022 msg: T

        "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#returns","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#max","title":"max?","text":"

        max?: number

        Optional maximum number of messages to deliver to the subscription before it is auto-unsubscribed.

        "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#queue","title":"queue?","text":"

        queue?: string

        Optional queue name (subscriptions on the same subject that use queues are horizontally load balanced when part of the same queue).

        "},{"location":"Frontend%20Development/api/nats/interfaces/SubOpts/#timeout","title":"timeout?","text":"

        timeout?: number

        Optional maximum number of milliseconds before a timer raises an error. This useful to monitor a subscription that is expected to yield messages. The timer is cancelled when the first message is received by the subscription.

        "},{"location":"Frontend%20Development/api/nats/type-aliases/MsgRequest/","title":"MsgRequest","text":"

        @wuespace/telestion / nats / MsgRequest

        MsgRequest: SeqMsgRequest | LastForMsgRequest | number

        "},{"location":"Frontend%20Development/api/nats/type-aliases/Subscription/","title":"Subscription","text":"

        @wuespace/telestion / nats / Subscription

        Subscription: Sub<Msg>

        Type alias for NATS core subscriptions

        "},{"location":"Frontend%20Development/api/nats/type-aliases/SubscriptionOptions/","title":"SubscriptionOptions","text":"

        @wuespace/telestion / nats / SubscriptionOptions

        SubscriptionOptions: SubOpts<Msg>

        Subscription Options

        "},{"location":"Frontend%20Development/api/user-data/","title":"Index","text":"

        @wuespace/telestion / user-data

        Types and utilities for interacting with the user data stored on the user\u2019s device.

        "},{"location":"Frontend%20Development/api/user-data/#example","title":"Example","text":"
        import { ... } from '@wuespace/telestion/user-data';\n
        "},{"location":"Frontend%20Development/api/user-data/#type-aliases","title":"Type Aliases","text":"
        • Dashboard
        • WidgetInstance
        "},{"location":"Frontend%20Development/api/user-data/#variables","title":"Variables","text":"
        • dashboardSchema
        • idSchema
        • layoutSchema
        • semverRegExp
        • userDataSchema
        • widgetInstanceSchema
        "},{"location":"Frontend%20Development/api/user-data/#functions","title":"Functions","text":"
        • getBlankUserData
        • getEmptyDashboard
        • getUserData
        • removeUserData
        • setUserData
        "},{"location":"Frontend%20Development/api/user-data/#references","title":"References","text":""},{"location":"Frontend%20Development/api/user-data/#userdata","title":"UserData","text":"

        Re-exports UserData

        "},{"location":"Frontend%20Development/api/user-data/functions/getBlankUserData/","title":"getBlankUserData","text":"

        @wuespace/telestion / user-data / getBlankUserData

        getBlankUserData(version): UserData

        Returns a new blank user data object.

        "},{"location":"Frontend%20Development/api/user-data/functions/getBlankUserData/#parameters","title":"Parameters","text":"

        \u2022 version: string

        the current application version

        "},{"location":"Frontend%20Development/api/user-data/functions/getBlankUserData/#returns","title":"Returns","text":"

        UserData

        "},{"location":"Frontend%20Development/api/user-data/functions/getEmptyDashboard/","title":"getEmptyDashboard","text":"

        @wuespace/telestion / user-data / getEmptyDashboard

        getEmptyDashboard(): readonly [string, Dashboard]

        Returns a new and empty dashboard with a unique id.

        "},{"location":"Frontend%20Development/api/user-data/functions/getEmptyDashboard/#returns","title":"Returns","text":"

        readonly [string, Dashboard]

        "},{"location":"Frontend%20Development/api/user-data/functions/getUserData/","title":"getUserData","text":"

        @wuespace/telestion / user-data / getUserData

        getUserData(): undefined | Object

        Retrieves user data from local storage.

        "},{"location":"Frontend%20Development/api/user-data/functions/getUserData/#returns","title":"Returns","text":"

        undefined | Object

        The user data if found in local storage, otherwise undefined.

        "},{"location":"Frontend%20Development/api/user-data/functions/removeUserData/","title":"removeUserData","text":"

        @wuespace/telestion / user-data / removeUserData

        removeUserData(): void

        Removes the user data from local storage.

        "},{"location":"Frontend%20Development/api/user-data/functions/removeUserData/#returns","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/user-data/functions/setUserData/","title":"setUserData","text":"

        @wuespace/telestion / user-data / setUserData

        setUserData(newUserData): void

        Sets the user data in the local storage based on the given input.

        "},{"location":"Frontend%20Development/api/user-data/functions/setUserData/#parameters","title":"Parameters","text":"

        \u2022 newUserData: Object

        The new user data to be set.

        \u2022 newUserData.dashboards: Record<string, { title: string; layout: string[][]; }>= undefined

        The user\u2019s dashboards.

        \u2022 newUserData.version: string= undefined

        The version of the client that created this user data.

        \u2022 newUserData.widgetInstances: Record<string, { type: string; configuration: Record<string, unknown>; }>= undefined

        The user\u2019s widget instances.

        "},{"location":"Frontend%20Development/api/user-data/functions/setUserData/#returns","title":"Returns","text":"

        void

        "},{"location":"Frontend%20Development/api/user-data/type-aliases/Dashboard/","title":"Dashboard","text":"

        @wuespace/telestion / user-data / Dashboard

        Dashboard: Object

        Represents a dashboard.

        "},{"location":"Frontend%20Development/api/user-data/type-aliases/Dashboard/#see","title":"See","text":"

        dashboardSchema

        "},{"location":"Frontend%20Development/api/user-data/type-aliases/Dashboard/#type-declaration","title":"Type declaration","text":""},{"location":"Frontend%20Development/api/user-data/type-aliases/Dashboard/#layout","title":"layout","text":"

        layout: string[][] = layoutSchema

        The layout of the dashboard.

        "},{"location":"Frontend%20Development/api/user-data/type-aliases/Dashboard/#title","title":"title","text":"

        title: string

        The title of the dashboard.

        "},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/","title":"WidgetInstance","text":"

        @wuespace/telestion / user-data / WidgetInstance

        WidgetInstance: Object

        Represents a widget instance.

        "},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/#see","title":"See","text":"

        widgetInstanceSchema

        "},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/#type-declaration","title":"Type declaration","text":""},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/#configuration","title":"configuration","text":"

        configuration: Record<string, unknown>

        The configuration of the widget.

        "},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/#type","title":"type","text":"

        type: string

        The type ID of the widget.

        This is used to determine which widget type to use to render the widget.

        "},{"location":"Frontend%20Development/api/user-data/type-aliases/WidgetInstance/#see_1","title":"See","text":"

        Widget.id

        "},{"location":"Frontend%20Development/api/user-data/variables/dashboardSchema/","title":"dashboardSchema","text":"

        @wuespace/telestion / user-data / dashboardSchema

        const dashboardSchema: ZodObject<Dashboard>

        Represents the schema for a dashboard.

        "},{"location":"Frontend%20Development/api/user-data/variables/idSchema/","title":"idSchema","text":"

        @wuespace/telestion / user-data / idSchema

        const idSchema: ZodString

        A regular expression that matches valid identifiers.

        Used for dashboard and widget instance IDs.

        "},{"location":"Frontend%20Development/api/user-data/variables/idSchema/#see","title":"See","text":"

        WidgetInstance

        "},{"location":"Frontend%20Development/api/user-data/variables/layoutSchema/","title":"layoutSchema","text":"

        @wuespace/telestion / user-data / layoutSchema

        const layoutSchema: ZodArray<ZodArray<ZodUnion<[ZodString, ZodLiteral<\".\">]>, \"many\">, \"many\">

        A schema that matches valid layout configurations.

        "},{"location":"Frontend%20Development/api/user-data/variables/semverRegExp/","title":"semverRegExp","text":"

        @wuespace/telestion / user-data / semverRegExp

        const semverRegExp: RegExp

        A regular expression that matches semantic version numbers.

        Taken from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string

        "},{"location":"Frontend%20Development/api/user-data/variables/userDataSchema/","title":"userDataSchema","text":"

        @wuespace/telestion / user-data / userDataSchema

        const userDataSchema: ZodObject<UserData>

        The schema for the user data.

        "},{"location":"Frontend%20Development/api/user-data/variables/userDataSchema/#see","title":"See","text":"

        UserData

        "},{"location":"Frontend%20Development/api/user-data/variables/widgetInstanceSchema/","title":"widgetInstanceSchema","text":"

        @wuespace/telestion / user-data / widgetInstanceSchema

        const widgetInstanceSchema: ZodObject<WidgetInstance>

        Represents the schema for a widget instance.

        "},{"location":"Frontend%20Development/api/user-data/variables/widgetInstanceSchema/#see","title":"See","text":"

        WidgetInstance

        "},{"location":"Frontend%20Development/api/utils/","title":"Index","text":"

        @wuespace/telestion / utils

        Various utility functions around building Telestion frontend apps.

        "},{"location":"Frontend%20Development/api/utils/#example","title":"Example","text":"
        import { ... } from '@wuespace/telestion/utils';\n
        "},{"location":"Frontend%20Development/api/utils/#index","title":"Index","text":""},{"location":"Frontend%20Development/api/utils/#functions","title":"Functions","text":"
        • generateDashboardId
        • isUserDataUpToDate
        • loadFileContents
        • wait
        "},{"location":"Frontend%20Development/api/utils/functions/generateDashboardId/","title":"generateDashboardId","text":"

        @wuespace/telestion / utils / generateDashboardId

        generateDashboardId(): string

        Generates a unique identifier for a dashboard.

        "},{"location":"Frontend%20Development/api/utils/functions/generateDashboardId/#returns","title":"Returns","text":"

        string

        The generated dashboard identifier.

        "},{"location":"Frontend%20Development/api/utils/functions/isUserDataUpToDate/","title":"isUserDataUpToDate","text":"

        @wuespace/telestion / utils / isUserDataUpToDate

        isUserDataUpToDate(userData, currentVersion): boolean

        Checks if the user data is up-to-date with the current version of the application.

        "},{"location":"Frontend%20Development/api/utils/functions/isUserDataUpToDate/#parameters","title":"Parameters","text":"

        \u2022 userData: undefined | Object

        the user data to compare with the application version

        \u2022 currentVersion: string

        the current version of the application

        "},{"location":"Frontend%20Development/api/utils/functions/isUserDataUpToDate/#returns","title":"Returns","text":"

        boolean

        "},{"location":"Frontend%20Development/api/utils/functions/loadFileContents/","title":"loadFileContents","text":"

        @wuespace/telestion / utils / loadFileContents

        loadFileContents(file, encoding): Promise<string>

        Loads the contents of a specified file.

        "},{"location":"Frontend%20Development/api/utils/functions/loadFileContents/#parameters","title":"Parameters","text":"

        \u2022 file: File

        The file object to load contents from.

        \u2022 encoding: string= 'utf-8'

        The encoding to use while reading the file. Default is UTF-8.

        "},{"location":"Frontend%20Development/api/utils/functions/loadFileContents/#returns","title":"Returns","text":"

        Promise<string>

        • A Promise that resolves with the contents of the file as a string. - If the file is empty, the Promise will be rejected with an error.
        "},{"location":"Frontend%20Development/api/utils/functions/wait/","title":"Wait","text":"

        @wuespace/telestion / utils / wait

        wait(timeout): Promise<void>

        Waits for the specified amount of time before resolving the returned promise.

        "},{"location":"Frontend%20Development/api/utils/functions/wait/#parameters","title":"Parameters","text":"

        \u2022 timeout: number

        The duration in milliseconds to wait before resolving.

        "},{"location":"Frontend%20Development/api/utils/functions/wait/#returns","title":"Returns","text":"

        Promise<void>

        A promise that resolves after the specified time has elapsed.

        "},{"location":"Frontend%20Development/api/widget/","title":"Index","text":"

        @wuespace/telestion / widget

        Everything you need for building and/or displaying widgets.

        "},{"location":"Frontend%20Development/api/widget/#example","title":"Example","text":"
        import { ... } from '@wuespace/telestion/widget';\n
        "},{"location":"Frontend%20Development/api/widget/#interfaces","title":"Interfaces","text":"
        • WidgetRendererProps
        "},{"location":"Frontend%20Development/api/widget/#variables","title":"Variables","text":"
        • widgetConfigContext
        "},{"location":"Frontend%20Development/api/widget/#functions","title":"Functions","text":"
        • WidgetRenderer
        • getWidgetById
        • getWidgets
        "},{"location":"Frontend%20Development/api/widget/#references","title":"References","text":""},{"location":"Frontend%20Development/api/widget/#widget","title":"Widget","text":"

        Re-exports Widget

        "},{"location":"Frontend%20Development/api/widget/#registerwidgets","title":"registerWidgets","text":"

        Re-exports registerWidgets

        "},{"location":"Frontend%20Development/api/widget/functions/WidgetRenderer/","title":"WidgetRenderer","text":"

        @wuespace/telestion / widget / WidgetRenderer

        WidgetRenderer(WidgetRendererProps): Element

        Renders a widget based on the provided widgetInstanceId.

        "},{"location":"Frontend%20Development/api/widget/functions/WidgetRenderer/#parameters","title":"Parameters","text":"

        \u2022 WidgetRendererProps: WidgetRendererProps

        The props for the WidgetRenderer.

        "},{"location":"Frontend%20Development/api/widget/functions/WidgetRenderer/#returns","title":"Returns","text":"

        Element

        The rendered widget.

        "},{"location":"Frontend%20Development/api/widget/functions/WidgetRenderer/#throws","title":"Throws","text":"

        Error If the widget instance is not found.

        "},{"location":"Frontend%20Development/api/widget/functions/getWidgetById/","title":"getWidgetById","text":"

        @wuespace/telestion / widget / getWidgetById

        getWidgetById(id): undefined | Widget<Record<string, unknown>>

        Retrieves a widget by its unique type ID.

        "},{"location":"Frontend%20Development/api/widget/functions/getWidgetById/#parameters","title":"Parameters","text":"

        \u2022 id: string

        The unique type ID of the widget.

        "},{"location":"Frontend%20Development/api/widget/functions/getWidgetById/#returns","title":"Returns","text":"

        undefined | Widget<Record<string, unknown>>

        The widget associated with the ID, or null if the widget is not found.

        "},{"location":"Frontend%20Development/api/widget/functions/getWidgets/","title":"getWidgets","text":"

        @wuespace/telestion / widget / getWidgets

        getWidgets(): Widget<Record<string, unknown>>[]

        Returns an array of all the widgets that are currently registered.

        "},{"location":"Frontend%20Development/api/widget/functions/getWidgets/#returns","title":"Returns","text":"

        Widget<Record<string, unknown>>[]

        An array containing all the widgets.

        "},{"location":"Frontend%20Development/api/widget/interfaces/WidgetRendererProps/","title":"WidgetRendererProps","text":"

        @wuespace/telestion / widget / WidgetRendererProps

        "},{"location":"Frontend%20Development/api/widget/interfaces/WidgetRendererProps/#properties","title":"Properties","text":""},{"location":"Frontend%20Development/api/widget/interfaces/WidgetRendererProps/#widgetinstanceid","title":"widgetInstanceId","text":"

        widgetInstanceId: string

        "},{"location":"Frontend%20Development/api/widget/variables/widgetConfigContext/","title":"widgetConfigContext","text":"

        @wuespace/telestion / widget / widgetConfigContext

        const widgetConfigContext: Context<unknown>

        "},{"location":"_writers-guide/","title":"Writer\u2019s Guide","text":""},{"location":"_writers-guide/#introduction","title":"Introduction","text":"

        This guide is intended to help you write documentation.

        "},{"location":"_writers-guide/#writing-style","title":"Writing Style","text":""},{"location":"_writers-guide/#general","title":"General","text":"
        • Use the active voice.
        • Use the present tense.
        • Use the second person.
        • Use the imperative mood.
        • Use they/them/their as singular pronouns.
        "},{"location":"_writers-guide/#markdown","title":"Markdown","text":""},{"location":"_writers-guide/#general_1","title":"General","text":"
        • Use the GitHub Flavored Markdown syntax.
        • Use the CommonMark specification.
        "},{"location":"_writers-guide/#headings","title":"Headings","text":"
        • Use # for headings.
        • Use ## for subheadings.
        • Use ### for sub-subheadings.
        "},{"location":"_writers-guide/#lists","title":"Lists","text":"
        • Use * for unordered lists.
        • Use 1. for ordered lists.
        • Use * for nested unordered lists.
        • Use 1. for nested ordered lists.
        "},{"location":"_writers-guide/#links","title":"Links","text":"
        • Use [text](url) for links.
        "},{"location":"_writers-guide/#internal-links","title":"Internal Links","text":"
        • Use relative links for internal links.
        • Use the .md extension for internal links.
        • Use the # symbol for internal links to (sub-) headings.

        Example

        [Telestion Website](https://telestion.wuespace.de)\n\n[Deployment Pre-requisites](Deployment/prerequesites.md)\n\n[Deployment Pre-requisites](Deployment/prerequesites.md#deployment-pre-requisites)\n
        "},{"location":"_writers-guide/#images","title":"Images","text":"
        • Use ![alt text](url) for images.
        • Write the alt text in sentence case.
        • Place images close to the text that references them.
        • Use the PNG format for images.
        • Use the SVG format for logos and icons.
        • Use the JPEG format for photographs.
        • Use the GIF format for animations.

        For images that can be inverted for the dark theme, use the following syntax:

        ![alt text](url){ .invertible }\n

        To add a caption to an image, use the following syntax:

        <figure markdown>\n![alt text](url)\n<figcaption>Image caption</figcaption>\n</figure>\n

        Example

        ![alt text](url)\n\n![alt text](url){ .invertible }\n\n<figure markdown>\n![alt text](url)\n<figcaption>Image caption</figcaption>\n</figure>\n
        "},{"location":"_writers-guide/#code-blocks","title":"Code Blocks","text":"
        • Use ``` for code blocks.
        • Use ```language for code blocks with syntax highlighting.
        • Use ```language title=\"name\" for code blocks with syntax highlighting and a title.

        Example

        ```java\npublic static void main(String[] args) {\n    System.out.println(\"Hello World!\");\n}\n```\n\n```java title=\"Hello World\"\npublic static void main(String[] args) {\n    System.out.println(\"Hello World!\");\n}\n```\n
        "},{"location":"_writers-guide/#admonitions","title":"Admonitions","text":"
        • Use !!! note for notes.
        • Use !!! tip for tips.
        • Use !!! warning for warnings.
        • Use !!! danger for dangers.
        • Use !!! example for examples.
        • Use !!! question for questions.

        Example

        !!! note\n    This is a note.\n\n!!! tip\n    This is a tip.\n\n!!! warning\n    This is a warning.\n\n!!! danger\n    This is a danger.\n\n!!! example\n    This is an example.\n\n!!! question\n    This is a question.\n
        "},{"location":"_writers-guide/#keyboard-shortcuts","title":"Keyboard Shortcuts","text":"
        • Use ++ for keyboard shortcuts.
        • Use ++ctrl+f++ for keyboard shortcuts with multiple keys.
        • Use lowercase letters for keyboard shortcuts.

        Example

        Press Ctrl+F to open the menu.

        Press ++ctrl+f++ to open the menu.\n
        "}]} \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index ce27021a..7667d1bc 100644 Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ