Files
2026-09-18 22:03:10 +07:00

4.3 KiB

Specification: natsClient_JS

The technical contract for the module's exports. Each item carries an SP-XXX ID and traces to a Requirement (FR/NFR) and Solution Design decision (SD).

1. Module Exports

  • connectionStatus — Svelte writable store of { state, message }.
  • setConfig(cfg) — inject config (broker/fileserver URLs).
  • getNats(opts) — establish the shared connection.
  • subscribe(subject, onMessage) — subscribe and decode.
  • publish(subject, payload, opts) — publish.
  • closeNats() — close and cleanup.
  • connectNATS(brokerUrl, cfg) — connect using a broker URL or config.
  • request(subject, payload, opts) — request/reply.
  • reply(subject, handler, opts) — reply handler.
  • sendMsghandlerRequest(subject, functioncall, args, config) — msghandler request.

2. API Contract

SP-001: getNats(opts)

getNats(opts?: { servers?: string }) => Promise<connection>
  • URL resolution precedence: opts.servers → import.meta.env.VITE_NATS_URL → config.nats_server_info.url → wss://natsws.yiem.cc.
  • Emits connecting then connected on connectionStatus.
  • Returns the NATS connection object.
  • Throws on connection failure. Traceability: FR-001, FR-007, SD-001, SD-002, SD-004

SP-002: subscribe(subject, onMessage)

subscribe(subject: string, onMessage: (parsed) => void) => Promise<{ unsubscribe(): Promise<void> }>
  • Auto-connects via getNats if not connected.
  • Decodes each message with StringCodec, then JSON.parse, falling back to { text }.
  • Registers the subscription in the Map registry for cleanup (SD-005). Traceability: FR-002, SD-003, SD-005

SP-003: publish(subject, payload, opts)

publish(subject: string, payload: object | string = {}, opts?: object) => Promise<void>
  • Auto-connects via getNats if not connected.
  • String payloads are sent verbatim; other payloads are JSON.stringifyed. Traceability: FR-003, SD-001, SD-003

SP-004: request(subject, payload, opts)

request(subject: string, payload: object | string, opts?: { timeout?: number }) => Promise<object>
  • Sends a request with nc.request, encoding non-strings via JSON.stringify.
  • Decodes the reply (JSON.parse, else { text }). Traceability: FR-004, SD-003

SP-005: reply(subject, handler, opts)

reply(subject: string, handler: (parsed, msg) => object | string, opts?: object)
  => Promise<{ unsubscribe(): Promise<void> }>
  • Invokes handler(parsed, msg) and publishes the returned value on m.subject. Traceability: FR-005, SD-005

SP-006: sendMsghandlerRequest(subject, functioncall, args, config)

sendMsghandlerRequest(subject: string, functioncall: string, args: object, config: object)
  => Promise<object>
  • Packs [[db_request, { functioncall, args }, "dictionary"]] via msghandlerCSR.smartpack.
  • Sends a request, unpacks via msghandlerCSR.smartunpack.
  • Returns the jsontable/dictionary data; throws if type === "text". Traceability: FR-006, SD-006

SP-007: closeNats()

closeNats() => Promise<void>
  • Unsubscribes every tracked subscription, clears reconnect timers, closes the connection. Traceability: FR-008, NFR-501, SD-005

SP-008: connectionStatus store

connectionStatus: Writable<{ state: "connecting" | "connected" | "disconnected" | "error", message: string }>

Traceability: FR-007, NFR-201, SD-004

3. Payload Format

All payloads are JSON text encoded via StringCodec:

  • Publish/request: JSON.stringify(payload) for objects; string sent verbatim.
  • Decode: JSON.parse(text), fallback { text }.

4. Msghandler Envelope Format

SP-010: Request envelope

Built by msghandlerCSR.smartpack(subject, [["db_request", { functioncall, args }, "dictionary"]], { broker_url, fileserver_url }).

SP-011: Response envelope

Returned by msghandlerCSR.smartunpack; .payloads is an array of [dataname, data, type]. sendMsghandlerRequest returns data when type is jsontable or dictionary, and throws when type === "text".

5. Error Codes

Condition Behavior Traceability
type === "text" in msghandler reply throw new Error(data) FR-006, SP-011
getNats fails sets error status, throws FR-001, SP-001
No jsontable/dictionary payload throw new Error('No valid response found') FR-006