Files
natsClient_JS/docs/2-solution_design.md
2026-09-18 22:03:10 +07:00

4.5 KiB

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

%% 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