# 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 ``` - 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 }> ``` - 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 ``` - Auto-connects via `getNats` if not connected. - String payloads are sent verbatim; other payloads are `JSON.stringify`ed. **Traceability**: FR-003, SD-001, SD-003 ### SP-004: request(subject, payload, opts) ``` request(subject: string, payload: object | string, opts?: { timeout?: number }) => Promise ``` - 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 }> ``` - 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 ``` - 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 ``` - 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 |