0

Publish message

by
Published today

Publish one message to a NATS subject, with optional headers. A string payload is sent as-is, anything else as JSON. With jetstream on, it waits for the stream's acknowledgement and returns the stream and sequence.

Script nats Verified

The script

Submitted by hugo989 Bun
Verified 8 hours ago
1
import {
2
  connect,
3
  headers as natsHeaders,
4
  jwtAuthenticator,
5
  nkeyAuthenticator,
6
} from "nats"
7

8
/**
9
 * Publish message
10
 * Publish one message to a NATS subject, with optional headers. A string payload is sent as-is, anything else as JSON. With jetstream on, it waits for the stream's acknowledgement and returns the stream and sequence.
11
 */
12
export async function main(
13
  auth: RT.Nats,
14
  subject: string,
15
  payload: any,
16
  headers: { [key: string]: string } | undefined,
17
  jetstream: boolean = false
18
) {
19
  if (payload === undefined) throw new Error("payload is required")
20
  // nats.js falls back to 127.0.0.1:4222 when given no server.
21
  const servers = (auth.servers ?? []).map((s) => s.trim()).filter((s) => s)
22
  if (!servers.length) throw new Error("The nats resource lists no servers")
23
  const a = auth.auth ?? { label: "NO_AUTH" }
24
  // Seeds and JWTs are often pasted from a .creds file with a trailing newline.
25
  const seed = (s: string) => new TextEncoder().encode(s.trim())
26
  const nc = await connect({
27
    servers,
28
    tls: auth.require_tls ? {} : undefined,
29
    token: a.label === "TOKEN" ? a.token : undefined,
30
    user: a.label === "USER_PASSWORD" ? a.user : undefined,
31
    pass: a.label === "USER_PASSWORD" ? a.password : undefined,
32
    authenticator:
33
      a.label === "NKEY"
34
        ? nkeyAuthenticator(seed(a.seed))
35
        : a.label === "JWT"
36
          ? jwtAuthenticator(a.jwt.trim(), seed(a.seed))
37
          : undefined,
38
    maxReconnectAttempts: 0,
39
  })
40
  try {
41
    const data = new TextEncoder().encode(
42
      typeof payload === "string" ? payload : JSON.stringify(payload)
43
    )
44
    const entries = Object.entries(headers ?? {})
45
    const h = entries.length ? natsHeaders() : undefined
46
    for (const [k, v] of entries) h!.append(k, String(v))
47
    if (jetstream) {
48
      const ack = await nc.jetstream().publish(subject, data, { headers: h })
49
      return {
50
        subject,
51
        stream: ack.stream,
52
        seq: ack.seq,
53
        duplicate: ack.duplicate,
54
      }
55
    }
56
    nc.publish(subject, data, { headers: h })
57
    // A round trip to the server: the message has left and was accepted.
58
    await nc.flush()
59
    return { subject }
60
  } finally {
61
    await nc.close()
62
  }
63
}
64