# Solution Design: natsClient_JS ## 1. Problem Decomposition | Problem | Description | User Impact | |---------|-------------|-------------| | P-001 | Consumers must manage a NATS connection lifecycle | Boilerplate, connection churn, dropped sockets | | P-002 | Consumers must decode/encode payloads | Manual `StringCodec`/`JSON` in every call site | | P-003 | Consumers need synchronous request/reply | Duplicated await-loop logic | | P-004 | Consumers need a server-side reply handler | No way to serve requests from the client | | P-005 | Consumers need msghandler envelope handling | Manual packing/unwrapping | | P-006 | Consumers need to know connection state | No way to drive a status indicator | | P-007 | Consumers need clean teardown | Leaked subscriptions and sockets | ## 2. Solution Approach A single shared NATS connection exposed as ES module exports, with one helper function per operation (subscribe, publish, request, reply, msghandler, close). Connection state flows into a reactive Svelte store so consumers can bind it directly. Envelope packing delegates to `msghandler-csr.js`, keeping this library focused on transport and lifecycle. ## 3. Decision Rationale | Decision ID | Decision | Rationale | Alternatives Rejected | |-------------|----------|-----------|----------------------| | SD-001 | Shared module-level connection (`nc`) | One socket serves every operation for the whole app | Per-call `connect` — connection churn | | SD-002 | URL resolution precedence chain | Predictable, layered configuration (opts → env → config → default) | A single required URL arg — no env/config fallback | | SD-003 | `StringCodec` + `JSON.stringify`/`JSON.parse` | Uniform text encoding for both directions | Per-consumer encoding logic | | SD-004 | Monitor `nc.status()` and `nc.closed()` | Reactive `connecting`/`connected`/`disconnected`/`error` states | Polling the connection | | SD-005 | Subscription registry (`Map`) | Centralized unsubscribe in `closeNats` | Scattered subscriptions with no cleanup | | SD-006 | Delegate msghandler to `msghandler-csr.js` | Separation of envelope codec from transport | Reimplementing envelope logic here | | SD-007 | Svelte store for `connectionStatus` | Framework-agnostic consumers get reactivity for free | Plain variable consumers must wire their own subscription | ## 4. High-Level Component Diagram ### C4 Level 2 - Container ```mermaid %% C4 Level 2 - Container flowchart LR app[Consuming App
Svelte app] -->|imports| natsClient[(natsClient.js)] natsClient -->|nats.ws WSS| nats[(NATS broker)] natsClient -->|smartpack/smartunpack| msg[(msghandler-csr.js)] natsClient -->|writable| store[(connectionStatus store)] ``` **Component Descriptions**: - **natsClient.js**: Shared connection + operation helpers (subscribe/publish/request/reply) + status store + msghandler delegation. - Links to requirements: FR-001..FR-008, NFR-101, NFR-201 - **msghandler-csr.js**: Envelope pack/unpack. - Links to requirements: FR-006 - **connectionStatus store**: Reactive `{state, message}` for the app. - Links to requirements: FR-007 ## 5. Alternatives Considered | Alternative | Pros | Cons | Decision | |-------------|------|------|----------| | Per-call connection | Isolated lifecycle | Connection churn, re-auth overhead | Rejected — SD-001 | | Manual decode at call site | No dependency | Duplicated error handling | Rejected — SD-003 | | Callbacks instead of async iterators | Familiar | Verbose, harder to cancel | Rejected — uses `for await` | ## 6. Risk Assessment | Risk | Impact | Probability | Mitigation | |------|--------|-------------|------------| | Broker unreachable at startup | Connection fails | Medium | `getNats` throws; consumer retries | | Decode error on a message | Lost message / crash | Low | `catch` around decode/parse/handler | | Reconnect never settles | Stuck `disconnected` | Low | `nc.status()` + `nc.closed()` monitoring | ## 7. Requirements Traceability | Solution Component | Requirement ID | Decision ID | Description | |-------------------|----------------|-------------|-------------| | Shared connection | FR-001, FR-003 | SD-001 | One socket for pub/sub and publish | | URL resolution | FR-001 | SD-002 | opts → env → config → default | | Message decode | FR-002 | SD-003 | StringCodec + JSON/text fallback | | Status tracking | FR-007 | SD-004 | status() + closed() monitor | | Subscription cleanup | FR-008 | SD-005 | Map registry | | msghandler | FR-006 | SD-006 | Delegation to msghandler-csr.js | | Reactive status | NFR-201 | SD-007 | Svelte store |