83 lines
4.5 KiB
Markdown
83 lines
4.5 KiB
Markdown
# 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<br/>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 |
|