Files
NATSBridge/docs/specification.md
2026-03-23 14:50:00 +07:00

45 KiB

Specification: NATSBridge

Version: 1.1.0
Date: 2026-03-23
Status: Active
Ground Truth: src/NATSBridge.jl
Specification Format: JSON Schema + AsyncAPI


1. Technical Contract Overview

This document defines the technical contract for NATSBridge - the cross-platform bi-directional data bridge that enables seamless communication between Julia, JavaScript, Python, Dart, and MicroPython applications using NATS as the message bus.

This specification serves as the single source of truth for:

  • Inputs: What data structures are accepted by smartsend()
  • Outputs: What data structures are returned by smartreceive()
  • Data Shapes: Exact field names, types, and constraints
  • Error Codes: Standardized error responses for failure scenarios

1.1 Requirements Traceability

Specification Section Requirement ID(s) Description
Section 2 (Message Envelope) FR-012, FR-013, NFR-101, NFR-102 Message envelope structure and validation
Section 3 (Payload Schema) FR-001, FR-002, FR-003, FR-004, NFR-101, NFR-102 Payload structure and field definitions
Section 4 (Payload Format) FR-006, FR-007 Tuple format for smartsend()
Section 5 (Enumerations) FR-003, FR-004, FR-006, NFR-101 Enumerations for transport and encoding
Section 6 (Transport Protocols) FR-003, FR-004, NFR-104, NFR-105 Direct and link transport protocols
Section 7 (Size Thresholds) FR-004, FR-005, NFR-104, NFR-105 Size thresholds for transport selection
Section 8 (NATS Subject Convention) FR-013, FR-014 NATS subject naming patterns
Section 9 (Error Handling) FR-010, FR-011, NFR-201, NFR-202, NFR-203 Error codes and exception handling
Section 10 (Serialization Rules) FR-001, FR-002, FR-003, FR-012, NFR-101, NFR-102 Serialization and encoding rules
Section 11 (API Contract) FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008, FR-009, FR-010, FR-011, FR-012, FR-013, FR-014 Function signatures for all platforms
Section 12 (File Server Interface) FR-008, FR-009, FR-010 Upload and download handler contracts
Section 13 (Platform-Specific Constraints) FR-005, FR-006, NFR-106, NFR-107 Platform-specific feature support
Section 14 (Implementation Files) FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007 Implementation file mapping
Section 15 (Message Flow) FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008, FR-009, FR-010, FR-011, FR-012, FR-013, FR-014 Mermaid diagrams for send/receive flows
Section 16 (Validation Rules) FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008, FR-009, FR-010, FR-011, FR-012, FR-013, FR-014 Envelope and payload validation rules
Section 17 (Test Contracts) FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008, FR-009, FR-010, FR-011, FR-012, FR-013, FR-014 Unit and integration test scenarios
Section 18 (Dependencies) FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008, FR-009, FR-010, FR-011, FR-012, FR-013, FR-014 Platform-specific dependencies
Section 19 (Change Log) N/A Version history and changes

2. Message Envelope Schema

Specification Versioning

Component Version Notes
Specification 1.0.0 Initial release
Protocol v1 Message envelope protocol version

Message Envelope Schema

Envelope Structure (JSON)

{
  "correlation_id": "string (UUID)",
  "msg_id": "string (UUID)",
  "timestamp": "string (ISO 8601 UTC)",
  "send_to": "string",
  "msg_purpose": "string",
  "sender_name": "string",
  "sender_id": "string (UUID)",
  "receiver_name": "string",
  "receiver_id": "string (UUID)",
  "reply_to": "string",
  "reply_to_msg_id": "string",
  "broker_url": "string",
  "metadata": "object",
  "payloads": [
    {
      "id": "string (UUID)",
      "dataname": "string",
      "payload_type": "string",
      "transport": "string",
      "encoding": "string",
      "size": "integer",
      "data": "string or URL",
      "metadata": "object"
    }
  ]
}

Field Definitions

Field Type Required Validation Description Requirement ID
correlation_id string Yes UUID v4 format Track message flow across distributed systems FR-011, NFR-401
msg_id string Yes UUID v4 format Unique identifier for this specific message FR-012, NFR-401
timestamp string Yes ISO 8601 UTC Message publication timestamp FR-012, NFR-401
send_to string Yes Non-empty string NATS subject/topic to publish the message to FR-013
msg_purpose string Yes Enum Purpose of the message FR-013
sender_name string Yes Non-empty string Name of the sender application FR-013
sender_id string Yes UUID v4 format Unique identifier for the sender FR-013
receiver_name string Yes Any string Name of the receiver (empty = broadcast) FR-013
receiver_id string Yes Any string UUID of the receiver (empty = broadcast) FR-013
reply_to string Yes Any string Topic where receiver should reply FR-013
reply_to_msg_id string Yes Any string Message ID this message is replying to FR-013
broker_url string Yes Valid URL NATS broker URL FR-013
metadata object No Any JSON object Message-level metadata NFR-401
payloads array Yes Non-empty array List of payload objects FR-012, FR-013

Payload Schema

Payload Structure (JSON)

{
  "id": "string (UUID)",
  "dataname": "string",
  "payload_type": "string",
  "transport": "string",
  "encoding": "string",
  "size": "integer",
  "data": "string or URL",
  "metadata": "object"
}

Payload Field Definitions

Field Type Required Validation Description Requirement ID
id string Yes UUID v4 format Unique identifier for this payload FR-012
dataname string Yes Non-empty string Name of the payload (e.g., login_image, user_data) FR-001, FR-002, FR-003
payload_type string Yes Enum Type of payload (see payload_type enum) FR-001, FR-002, FR-003, FR-006
transport string Yes Enum Transport method: direct or link FR-003, FR-004, NFR-104, NFR-105
encoding string Yes Enum Encoding method (see encoding enum) FR-001, FR-002, FR-003, FR-012
size integer Yes Positive integer Size of the payload in bytes FR-003, FR-004, NFR-104, NFR-105
data string or URL Yes Base64 string or URL Payload data (base64 for direct, URL for link) FR-003, FR-004, FR-008, FR-009, FR-010
metadata object No Any JSON object Payload-level metadata NFR-401

Payload Format

Tuple Format for smartsend()

The smartsend() function accepts data as an array of tuples with the format:

("data_name", data, "data_type")
Position Type Description Example
1 string Data name - identifier for the payload "msg", "login_image", "user_data"
2 any Actual data - content to be serialized "Hello", {"key": "value"}, DataFrame(...)
3 string Data type - must be in payload_type enum "text", "dictionary", "arrowtable"

Single Payload Example

# Julia
smartsend("/chat/user/v1/message", [("msg", "Hello World", "text")])
# Python
await smartsend("/chat/user/v1/message", [("msg", "Hello World", "text")])
// JavaScript
await smartsend("/chat/user/v1/message", [["msg", "Hello World", "text"]]);

Multiple Payloads Example

# Julia - Mixed text and binary data
data = [
    ("msg", "Hello", "text"),
    ("img", binary_data, "image")
]
smartsend("/agent/v1/process", data)
# Python - Mixed types
data = [
    ("msg", "Hello", "text"),
    ("img", binary_data, "image")
]
await smartsend("/agent/v1/process", data)

Data Type Mapping

Platform Input Type Data Type String
All String "text"
All Dict/Object "dictionary"
Desktop DataFrame "arrowtable" or "jsontable"
Browser Array of objects "jsontable" (only table type)
All Array of objects "jsontable"
All Uint8Array/Buffer/bytes "binary"
Desktop Arrow.Table "arrowtable"
All Image/Audio/Video binary "image", "audio", "video"

Enumerations

msg_purpose Enum

Value Description
ACK Acknowledgment of successful message processing
NACK Negative acknowledgment of message processing failure
updateStatus Status update message
shutdown Graceful shutdown request
chat Chat/message payload
command Command payload
event Event payload

payload_type Enum

Value Description Supported Platforms Encoding Options
text Plain text string All base64
dictionary JSON object/dictionary All base64, json
arrowtable Apache Arrow IPC table Desktop (Julia/Python/Node.js/Dart) base64, arrow-ipc
jsontable JSON array of objects All (including Browser/Dart Web) base64, json
image Binary image data All base64
audio Binary audio data All base64
video Binary video data All base64
binary Generic binary data All base64

transport Enum

Value Description Data Format Use Case
direct Payload sent directly via NATS Base64-encoded string Payloads < size_threshold
link Payload uploaded to file server HTTP URL Payloads ≥ size_threshold

encoding Enum

Value Description Payload Types
none No additional encoding Link transport URLs
base64 Base64 encoding Text, binary, image, audio, video
json JSON encoding Dictionary, jsontable
arrow-ipc Apache Arrow IPC format Arrowtable

Transport Protocols

Direct Transport Protocol

When transport = "direct", the data field contains a Base64-encoded string of the serialized payload.

Flow:

  1. Serialize payload according to payload_type
  2. Encode serialized bytes as Base64
  3. Include Base64 string in data field

Example:

{
  "transport": "direct",
  "encoding": "base64",
  "size": 11,
  "data": "SGVsbG8gV29ybGQ="
}

When transport = "link", the data field contains a URL pointing to the uploaded payload.

Flow:

  1. Serialize payload according to payload_type
  2. Upload to HTTP file server (e.g., Plik)
  3. Include returned URL in data field

Example:

{
  "transport": "link",
  "encoding": "none",
  "size": 1000000,
  "data": "http://localhost:8080/file/3F62E/4AgGT/data.zip"
}

Size Thresholds

Desktop Platforms (Julia/JS/Python)

Platform Size Threshold Notes
Desktop 500,000 bytes (0.5MB) Default threshold

MicroPython Platform

Platform Size Threshold Maximum Payload Notes
MicroPython 100,000 bytes (100KB) 50,000 bytes Hard limit due to memory constraints

NATS Subject Convention

Subject Naming Pattern

<scope>/<service>/<version>/<operation>

Examples:

  • /agent/wine/api/v1/prompt - AI agent prompt endpoint
  • /chat/user/v1/message - User chat message
  • /system/worker/v1/status - Worker status update

Subject Wildcards

Wildcard Description Example
* Single-level wildcard /chat/user/v1/* matches /chat/user/v1/message
> Multi-level wildcard /chat/user/v1/> matches all /chat/user/v1/* subjects

Error Handling

Error Response Format

{
  "error": {
    "code": "string",
    "message": "string",
    "details": "object"
  }
}

Error Codes

Code HTTP Status Description Recovery Requirement ID
INVALID_ENVELOPE 400 Message envelope validation failed Fix envelope structure FR-012, FR-013, FR-014
INVALID_PAYLOAD_TYPE 400 Unsupported payload type Use supported payload_type FR-001, FR-002, FR-003, FR-006
INVALID_TRANSPORT 400 Unsupported transport type Use direct or link FR-003, FR-004, FR-006
UPLOAD_FAILED 500 File server upload failed Retry or use direct transport FR-008, FR-009
DOWNLOAD_FAILED 503 File server download failed Retry with exponential backoff FR-010, FR-011, NFR-201, NFR-202
NATS_CONNECTION_FAILED 503 NATS connection failed Check NATS server availability FR-013, FR-014, NFR-201, NFR-203
DESERIALIZATION_ERROR 500 Payload deserialization failed Check payload_type matches data FR-001, FR-002, FR-003, FR-012
SIZE_EXCEEDED 413 Payload exceeds maximum size Split payload or use link transport FR-003, FR-004, FR-005, NFR-104, NFR-105

Exception Handling

Scenario Handler Retry Policy Requirement ID
File server unavailable Retry up to 5 times Exponential backoff (100ms → 5000ms) FR-010, NFR-202
NATS publish failure Connection auto-reconnect TCP-level reconnection FR-013, FR-014, NFR-201, NFR-203
Deserialization error Log correlation ID and throw No retry (data corruption) FR-001, FR-002, FR-003, FR-012, NFR-401
Memory overflow (MicroPython) Reject payloads >50KB No retry (client-side check) FR-005, NFR-106

Serialization Rules

Text Serialization

Platform Input Type Serialization Encoding
All String UTF-8 bytes Base64

Dictionary Serialization

Platform Input Type Serialization Encoding
All Object/Dict JSON string Base64 or direct JSON

Arrow Table Serialization

Platform Input Type Serialization Encoding
Desktop DataFrame Arrow IPC stream Base64 or arrow-ipc
Desktop Arrow.Table Arrow IPC stream Base64 or arrow-ipc
MicroPython Not supported N/A

JSON Table Serialization

Platform Input Type Serialization Encoding
All Vector{Dict}/Array<Object> JSON array Base64 or direct JSON
Desktop pandas.DataFrame JSON array Base64 or direct JSON

Binary Serialization

Platform Input Type Serialization Encoding
All Uint8Array/Buffer/bytes Raw bytes Base64

API Contract

smartsend Function Signature

Julia

function smartsend(
    subject::String,
    data::AbstractArray{Tuple{String, Any, String}};
    broker_url::String = "nats://localhost:4222",
    fileserver_url::String = "http://localhost:8080",
    fileserver_upload_handler::Function = plik_oneshot_upload,
    size_threshold::Int = 500_000,
    correlation_id::String = string(uuid4()),
    msg_purpose::String = "chat",
    sender_name::String = "NATSBridge",
    receiver_name::String = "",
    receiver_id::String = "",
    reply_to::String = "",
    reply_to_msg_id::String = "",
    is_publish::Bool = true,
    NATS_connection::Union{NATS.Connection, Nothing} = nothing,
    msg_id::String = string(uuid4()),
    sender_id::String = string(uuid4())
)::Tuple{msg_envelope_v1, String}

Python

async def smartsend(
    subject: str,
    data: List[Tuple[str, Any, str]],
    broker_url: str = "nats://localhost:4222",
    fileserver_url: str = "http://localhost:8080",
    fileserver_upload_handler: Callable = plik_oneshot_upload,
    size_threshold: int = 500_000,
    correlation_id: str = None,
    msg_purpose: str = "chat",
    sender_name: str = "NATSBridge",
    receiver_name: str = "",
    receiver_id: str = "",
    reply_to: str = "",
    reply_to_msg_id: str = "",
    is_publish: bool = True,
    nats_connection: Any = None,
    msg_id: str = None,
    sender_id: str = None
) -> Tuple[Dict, str]:

JavaScript (Node.js)

async function smartsend(
    subject: string,
    data: Array<[string, any, string]>,
    options?: {
        broker_url?: string;
        fileserver_url?: string;
        fileserver_upload_handler?: Function;
        size_threshold?: number;
        correlation_id?: string;
        msg_purpose?: string;
        sender_name?: string;
        receiver_name?: string;
        receiver_id?: string;
        reply_to?: string;
        reply_to_msg_id?: string;
        is_publish?: boolean;
        nats_connection?: NATS.Connection;
        msg_id?: string;
        sender_id?: string;
    }
): Promise<[Object, string]>;

JavaScript (Browser)

async function smartsend(
    subject: string,
    data: Array<[string, any, string]>,
    options?: {
        broker_url?: string;
        fileserver_url?: string;
        fileserver_upload_handler?: Function;
        size_threshold?: number;
        correlation_id?: string;
        msg_purpose?: string;
        sender_name?: string;
        receiver_name?: string;
        receiver_id?: string;
        reply_to?: string;
        reply_to_msg_id?: string;
        is_publish?: boolean;
        nats_connection?: NATSClient | NATS.Connection;
        msg_id?: string;
        sender_id?: string;
    }
): Promise<[Object, string]>;

// NATSClient class for connection management
class NATSClient {
    constructor(url: string, keepAlive?: boolean);
    connect(): Promise<NATS.Connection>;
    publish(subject: string, message: string, correlationId: string): Promise<void>;
    close(): Promise<void>;
    getConnection(): NATS.Connection | null;
    isConnected(): boolean;
}

// NATSConnectionPool for managing multiple connections
class NATSConnectionPool {
    constructor(url: string, maxSize?: number);
    acquire(): Promise<NATSClient>;
    release(client: NATSClient): void;
    closeAll(): Promise<void>;
}

// publishMessage function for manual publishing
async function publishMessage(
    brokerUrlOrClient: string | NATSClient | NATS.Connection,
    subject: string,
    message: string,
    correlationId: string,
    closeConnection?: boolean
): Promise<void>;

MicroPython

def smartsend(
    subject: str,
    data: List[Tuple[str, Any, str]],
    **kwargs
) -> Tuple[Dict, str]:

Dart (Desktop/Flutter)

Future<[Map<String, dynamic>, String]> smartsend(
  String subject,
  List<List<dynamic>> data, {
  String brokerUrl = 'nats://localhost:4222',
  String fileserverUrl = 'http://localhost:8080',
  Function? fileserverUploadHandler,
  int sizeThreshold = 500000,
  String? correlationId,
  String msgPurpose = 'chat',
  String senderName = 'NATSBridge',
  String receiverName = '',
  String receiverId = '',
  String replyTo = '',
  String replyToMsgId = '',
  bool isPublish = true,
  dynamic natsConnection,
  String? msgId,
  String? senderId,
}) async {
  // Returns [envelope, jsonString]
}

Dart Web

Future<[Map<String, dynamic>, String]> smartsend(
  String subject,
  List<List<dynamic>> data, {
  String brokerUrl = 'nats://localhost:4222',
  String fileserverUrl = 'http://localhost:8080',
  Function? fileserverUploadHandler,
  int sizeThreshold = 500000,
  String? correlationId,
  String msgPurpose = 'chat',
  String senderName = 'NATSBridge',
  String receiverName = '',
  String receiverId = '',
  String replyTo = '',
  String replyToMsgId = '',
  bool isPublish = true,
  dynamic natsConnection,
  String? msgId,
  String? senderId,
}) async {
  // Returns [envelope, jsonString]
}

smartreceive Function Signature

Julia

function smartreceive(
    msg::NATS.Msg;
    fileserver_download_handler::Function = _fetch_with_backoff,
    max_retries::Int = 5,
    base_delay::Int = 100,
    max_delay::Int = 5000
)::JSON.Object{String, Any}

Python

async def smartreceive(
    msg: Any,
    fileserver_download_handler: Callable = fetch_with_backoff,
    max_retries: int = 5,
    base_delay: int = 100,
    max_delay: int = 5000
) -> Dict[str, Any]:

JavaScript (Node.js)

async function smartreceive(
    msg: Object,
    options?: {
        fileserver_download_handler?: Function;
        max_retries?: number;
        base_delay?: number;
        max_delay?: number;
    }
): Promise<Object>;

JavaScript (Browser)

async function smartreceive(
    msg: Object,
    options?: {
        fileserver_download_handler?: Function;
        max_retries?: number;
        base_delay?: number;
        max_delay?: number;
    }
): Promise<Object>;

MicroPython

def smartreceive(msg: Any, **kwargs) -> Dict[str, Any]:

Dart (Desktop/Flutter)

Future<Map<String, dynamic>> smartreceive(
  Map<String, dynamic> msg, {
  Function? fileserverDownloadHandler,
  int maxRetries = 5,
  int baseDelay = 100,
  int maxDelay = 5000,
}) async {
  // Returns envelope with processed payloads
}

Dart Web

Future<Map<String, dynamic>> smartreceive(
  Map<String, dynamic> msg, {
  Function? fileserverDownloadHandler,
  int maxRetries = 5,
  int baseDelay = 100,
  int maxDelay = 5000,
}) async {
  // Returns envelope with processed payloads
}

File Server Interface

Upload Handler Contract

Function Signature:

function fileserver_upload_handler(
    file_server_url::String,
    dataname::String,
    data::Vector{UInt8}
)::Dict{String, Any}

Return Format:

{
  "status": 200,
  "uploadid": "string",
  "fileid": "string",
  "url": "string"
}

Required Keys:

Key Type Description
status integer HTTP response status code
uploadid string Upload session identifier
fileid string File identifier within session
url string Full download URL

Download Handler Contract

Function Signature:

function fileserver_download_handler(
    url::String,
    max_retries::Int,
    base_delay::Int,
    max_delay::Int,
    correlation_id::String
)::Vector{UInt8}

Retry Policy:

  • Initial delay: base_delay milliseconds
  • Maximum delay: max_delay milliseconds
  • Multiplier: 2x per retry
  • Maximum retries: max_retries

Platform-Specific Constraints

Desktop (Julia/Python/Node.js/Dart)

Feature Status Notes
Arrow IPC Supported Requires Arrow.jl/pyarrow/dart-arrow
JSON table Supported Human-readable format
File server upload Supported HTTP/HTTPS
File server download Supported HTTP/HTTPS
Size threshold 500KB Configurable

Browser (JavaScript)

Feature Status Notes
Arrow IPC Not supported Apache Arrow not browser-compatible
JSON table Supported Only table type available in browser
File server upload Supported HTTP/HTTPS
File server download Supported HTTP/HTTPS
Size threshold 500KB Configurable

Dart Desktop (Dart SDK)

Feature Status Notes
Arrow IPC Supported Requires dart-arrow package
JSON table Supported Human-readable format
File server upload Supported HTTP/HTTPS
File server download Supported HTTP/HTTPS
Size threshold 500KB Configurable

Dart Flutter (Dart SDK)

Feature Status Notes
Arrow IPC Supported Requires dart-arrow package
JSON table Supported Human-readable format
File server upload Supported HTTP/HTTPS
File server download Supported HTTP/HTTPS
Size threshold 500KB Configurable

Dart Web (Dart SDK)

Feature Status Notes
Arrow IPC Not supported Apache Arrow not browser-compatible
JSON table Supported Only table type available in browser
File server upload Supported HTTP/HTTPS
File server download Supported HTTP/HTTPS
Size threshold 500KB Configurable

MicroPython

Feature Status Notes
Arrow IPC Not supported Memory constraints
JSON table ⚠️ Limited Only direct transport
File server upload Not implemented Placeholder only
File server download Not implemented Placeholder only
Size threshold 100KB Hard limit enforced
Max payload 50KB Hard limit enforced

Implementation Files

File Platform Features Notes
src/NATSBridge.jl Julia Full feature set, Arrow IPC, multiple dispatch Ground truth implementation
src/natsbridge_ssr.js Node.js Arrow IPC, async/await Server-side JavaScript
src/natsbridge_csr.js Browser JSON table only, WebSocket NATS Client-side rendering
src/natsbridge.py Python Arrow IPC, async/await Desktop Python
src/natsbridge.dart Dart Full feature set, Arrow IPC, async/await Desktop/Flutter/Web
src/natsbridge_mpy.py MicroPython Limited to direct transport Memory-constrained

Browser Implementation Notes

The browser implementation (src/natsbridge_csr.js) has the following constraints:

Constraint Reason Workaround
No Apache Arrow IPC Browser-incompatible dependency Use jsontable for tabular data
WebSocket NATS only Browser cannot use TCP directly Use ws:// or wss:// broker URLs
Fetch API for HTTP Browser fetch() API only Compatible with Plik and other HTTP servers

Payload Type Availability by Platform

Payload Type Julia Node.js Browser Python Dart MicroPython
text
dictionary
arrowtable
jsontable ⚠️
image
audio
video
binary

Message Flow

Sending Flow

flowchart TD
    A[User calls smartsend subject data] --> B[Serialize payload according to payload_type]
    B --> C{Calculate serialized size}
    C -->|Size < Threshold| D[Direct Transport: Encode as Base64]
    C -->|Size >= Threshold| E[Link Transport: Upload to file server]
    D --> F[Build envelope with metadata]
    E --> F
    F --> G[Convert envelope to JSON string]
    G --> H[Publish to NATS subject]
    H --> I[Return envelope and JSON string to caller]
    
    style A fill:#f9f9f9,stroke:#333
    style I fill:#e0e7ff,stroke:#3b82f6
    style D fill:#d1fae5,stroke:#10b981
    style E fill:#fef3c7,stroke:#f59e0b

Receiving Flow

flowchart TD
    A[NATS message arrives] --> B[Parse JSON envelope]
    B --> C[For each payload: Check transport type]
    C -->|transport == direct| D[Direct Transport: Extract Base64]
    C -->|transport == link| E[Link Transport: Fetch from URL]
    D --> F[Decode Base64]
    E --> G[Fetch with exponential backoff]
    F --> H[Deserialize based on payload_type]
    G --> H
    H --> I[Build payloads array]
    I --> J[Replace payloads array with deserialized tuples]
    J --> K[Return envelope with processed payloads]
    
    style A fill:#f9f9f9,stroke:#333
    style K fill:#e0e7ff,stroke:#3b82f6
    style D fill:#d1fae5,stroke:#10b981
    style E fill:#fef3c7,stroke:#f59e0b

Validation Rules

Envelope Validation

Rule Condition Error Code Requirement ID
Required fields present correlation_id, msg_id, timestamp, send_to, payloads INVALID_ENVELOPE FR-012, FR-013
Valid UUID format correlation_id, msg_id, sender_id, receiver_id INVALID_ENVELOPE FR-011, FR-012, NFR-401
Valid timestamp format ISO 8601 UTC INVALID_ENVELOPE FR-012, NFR-401
Non-empty payloads array length(payloads) > 0 INVALID_ENVELOPE FR-012, FR-013

Payload Validation

Rule Condition Error Code Requirement ID
Valid payload_type Must be in payload_type enum INVALID_PAYLOAD_TYPE FR-001, FR-002, FR-003, FR-006
Valid transport Must be direct or link INVALID_TRANSPORT FR-003, FR-004, FR-006
Valid encoding Must match payload_type and transport INVALID_TRANSPORT FR-001, FR-002, FR-003, FR-012
Positive size size > 0 INVALID_PAYLOAD FR-003, FR-004, NFR-104, NFR-105
Valid Base64 for direct data matches Base64 pattern DESERIALIZATION_ERROR FR-001, FR-002, FR-003, FR-012
Valid URL for link data matches HTTP(S) URL pattern DOWNLOAD_FAILED FR-008, FR-009, FR-010

Test Contracts

Unit Test Validation

Test Input Expected Output Notes Requirement ID
Text round-trip ("msg", "Hello", "text") ("msg", "Hello", "text") String serialization FR-001, FR-012, NFR-101, NFR-102
Dictionary round-trip ("data", {"key": "value"}, "dictionary") ("data", {"key": "value"}, "dictionary") JSON object round-trip FR-002, FR-012, NFR-101, NFR-102
Arrow table round-trip ("table", arrow_table_data, "arrowtable") ("table", arrow_table_data, "arrowtable") Arrow IPC round-trip FR-002, FR-012, NFR-101, NFR-102
JSON table round-trip ("table", [{"a":1},{"b":2}], "jsontable") ("table", [{"a":1},{"b":2}], "jsontable") JSON array of objects FR-001, FR-002, FR-006, FR-012
Mixed payloads [("msg", "Hello", "text"), ("imgname", bytes, "binary")] [("msg", "Hello", "text"), ("imgname", bytes, "binary")] Multiple payload types FR-006, FR-007
Large payload ("data", rand(10_000_000), "arrowtable") ("data", URL, "arrowtable") with link transport File server upload FR-003, FR-004, FR-008, FR-009, NFR-104, NFR-105

Platform-Specific Notes:

  • Julia: Use Dict, Vector{Dict}, or convert DataFrame to dictionary for testing
  • Python: Use dict, list[dict], or convert pandas.DataFrame to dictionary for testing
  • JavaScript: Use plain objects {} and arrays []
  • MicroPython: Use plain dict and list (limited to JSON table and text types)

Integration Test Scenarios

Scenario Platforms Payloads Size Mix Transport Expected Result Requirement ID
Single text (small) All text Small direct Round-trip successful FR-001, FR-012, NFR-101, NFR-102
Single dictionary (small) All dictionary Small direct Round-trip successful FR-002, FR-012, NFR-101, NFR-102
Single arrow table (small) Julia/JS/Python arrowtable Small direct Arrow IPC round-trip FR-002, FR-012, NFR-101, NFR-102
Single JSON table (small) All jsontable Small direct Dictionary array round-trip FR-001, FR-002, FR-006, FR-012
Single image (small) All image Small direct Binary round-trip FR-001, FR-006, FR-012
Single audio (small) All audio Small direct Binary round-trip FR-001, FR-006, FR-012
Single video (small) All video Small direct Binary round-trip FR-001, FR-006, FR-012
Single binary (small) All binary Small direct Binary round-trip FR-001, FR-006, FR-012
Single text (large) All text Large link File server upload/download FR-003, FR-004, FR-008, FR-009, NFR-104, NFR-105
Single JSON table (large) All jsontable Large link File server upload/download FR-003, FR-004, FR-008, FR-009, NFR-104, NFR-105
Single image (large) All image Large link File server upload/download FR-003, FR-004, FR-008, FR-009, NFR-104, NFR-105
Ultimate Test Julia/JS/Python text (small) + dictionary (small) + arrowtable (small) + jsontable (small) + image (small) + audio (small) + video (small) + binary (small) + text (large) + dictionary (large) + arrowtable (large) + jsontable (large) + image (large) Mixed direct/link All payloads preserved with correct transport FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008, FR-009, FR-010, FR-011, FR-012, FR-013, FR-014
Ultimate Test MicroPython text (small) + dictionary (small) + text (large) + dictionary (large) Mixed direct Limited to text/dictionary with direct transport only FR-005, FR-006, FR-012
Cross-platform JSON table All jsontable Small direct Dictionary array round-trip FR-001, FR-002, FR-006, FR-012
MicroPython ↔ Desktop MicroPython ↔ Desktop text/dictionary Small direct Limited payload types FR-005, FR-006, FR-012
Desktop ↔ Desktop (all combos) Julia↔JS↔Python All types Small/Large direct/link Full compatibility FR-001, FR-002, FR-003, FR-004, FR-005, FR-006, FR-007, FR-012, FR-013, FR-014

Dependencies

Required Dependencies by Platform

Platform Package Version Purpose
Julia NATS.jl Latest NATS client
Julia JSON.jl Latest JSON serialization
Julia Arrow.jl Latest Arrow IPC support
Julia HTTP.jl Latest HTTP file server
Julia UUIDs.jl Latest UUID generation
Node.js nats Latest NATS client (TCP)
Node.js node-fetch Latest HTTP file server
Browser nats.ws Latest NATS client (WebSocket)
Browser nats Latest NATS client (for bundling)
Python nats-py Latest NATS client
Python aiohttp Latest HTTP file server
Python pyarrow Latest Arrow IPC support
Dart nats Latest NATS client
Dart http Latest HTTP file server
Dart uuid Latest UUID generation
Dart dart-arrow Latest Arrow IPC support (Desktop/Flutter)
MicroPython builtin N/A Limited implementation

Optional Dependencies

Platform Package Purpose
Julia DataFrames.jl DataFrame support
Python pandas DataFrame support

Change Log

Date Version Changes
2026-03-15 1.1.0 Browser connection management
- - Added NATSClient class with keepAlive support
- - Added NATSConnectionPool for connection reuse
- - Added publishMessage function with closeConnection option
- - Added nats.ws to browser dependencies
2026-03-13 1.0.0 Initial specification
- - Message envelope schema defined
- - Payload schema with transport modes
- - Enumerations for payload_type, transport, encoding
- - Size thresholds for desktop/MicroPython
- - Error codes and validation rules
- - API contracts for all platforms

References

20.1 Documentation Artifacts

Document Purpose Requirements Traceability
docs/requirements.md Business requirements and user stories FR-001 through FR-014, NFR-101 through NFR-405
docs/specification.md Technical contract for NATSBridge This document
docs/ui-specification.md UI specification for client applications UI components for data entry and display
docs/walkthrough.md End-to-end system flow Traceability from user journey to technical implementation
docs/architecture.md System architecture diagrams Component interaction and data flow
docs/validation.md CI/CD validation rules Contract testing and spec compliance
docs/runbook.md Operational runbook Deployment, scaling, and troubleshooting

20.2 Implementation Files

File Platform Features Requirements Traceability
src/NATSBridge.jl Julia Full feature set, Arrow IPC, multiple dispatch FR-001 through FR-014, NFR-101 through NFR-405
src/natsbridge_ssr.js Node.js Arrow IPC, async/await FR-001 through FR-014, NFR-101 through NFR-405
src/natsbridge_csr.js Browser JSON table only, WebSocket NATS FR-001 through FR-014, NFR-101 through NFR-405
src/natsbridge.py Python Arrow IPC, async/await FR-001 through FR-014, NFR-101 through NFR-405
src/natsbridge_mpy.py MicroPython Limited to direct transport FR-005, FR-006, FR-012

20.3 External Dependencies

Platform Package Version Purpose Requirements Traceability
Julia NATS.jl Latest NATS client FR-013, FR-014, NFR-201
Julia JSON.jl Latest JSON serialization FR-012, NFR-101, NFR-102
Julia Arrow.jl Latest Arrow IPC support FR-002, FR-012
Julia HTTP.jl Latest HTTP file server FR-008, FR-009
Julia UUIDs.jl Latest UUID generation FR-011, NFR-401
Node.js nats Latest NATS client (TCP) FR-013, FR-014
Node.js node-fetch Latest HTTP file server FR-008, FR-009
Browser nats.ws Latest NATS client (WebSocket) FR-013, FR-014
Browser nats Latest NATS client (for bundling) FR-013, FR-014
Python nats-py Latest NATS client FR-013, FR-014
Python aiohttp Latest HTTP file server FR-008, FR-009
Python pyarrow Latest Arrow IPC support FR-002, FR-012
MicroPython builtin N/A Limited implementation FR-005, FR-006

21. Change Log

Date Version Changes Requirement ID(s)
2026-03-23 1.1.0 Updated to ASG Framework specification guidelines All
2026-03-15 1.1.0 Browser connection management FR-001 through FR-014
2026-03-13 1.0.0 Initial specification FR-001 through FR-014, NFR-101 through NFR-405

Appendix

A. Complete JSON Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "NATSBridge Envelope",
  "type": "object",
  "properties": {
    "correlation_id": {
      "type": "string",
      "pattern": "^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$",
      "description": "UUID v4 format for tracking message flow"
    },
    "msg_id": {
      "type": "string",
      "pattern": "^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$",
      "description": "Unique message identifier"
    },
    "timestamp": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$",
      "description": "ISO 8601 UTC timestamp"
    },
    "send_to": {
      "type": "string",
      "minLength": 1,
      "description": "NATS subject to publish to"
    },
    "msg_purpose": {
      "type": "string",
      "enum": ["ACK", "NACK", "updateStatus", "shutdown", "chat", "command", "event"],
      "description": "Purpose of the message"
    },
    "sender_name": {
      "type": "string",
      "minLength": 1,
      "description": "Sender application name"
    },
    "sender_id": {
      "type": "string",
      "pattern": "^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$",
      "description": "Sender UUID"
    },
    "receiver_name": {
      "type": "string",
      "description": "Receiver name (empty = broadcast)"
    },
    "receiver_id": {
      "type": "string",
      "pattern": "^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$|^$",
      "description": "Receiver UUID (empty = broadcast)"
    },
    "reply_to": {
      "type": "string",
      "description": "Topic for reply messages"
    },
    "reply_to_msg_id": {
      "type": "string",
      "description": "Message ID being replied to"
    },
    "broker_url": {
      "type": "string",
      "pattern": "^nats://[^\\s]+$",
      "description": "NATS broker URL"
    },
    "metadata": {
      "type": "object",
      "description": "Message-level metadata"
    },
    "payloads": {
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/definitions/Payload"
      }
    }
  },
  "required": ["correlation_id", "msg_id", "timestamp", "send_to", "msg_purpose", "sender_name", "sender_id", "receiver_name", "receiver_id", "reply_to", "reply_to_msg_id", "broker_url", "payloads"],
  "definitions": {
    "Payload": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$"
        },
        "dataname": {
          "type": "string",
          "minLength": 1
        },
        "payload_type": {
          "type": "string",
          "enum": ["text", "dictionary", "arrowtable", "jsontable", "image", "audio", "video", "binary"]
        },
        "transport": {
          "type": "string",
          "enum": ["direct", "link"]
        },
        "encoding": {
          "type": "string",
          "enum": ["none", "base64", "json", "arrow-ipc"]
        },
        "size": {
          "type": "integer",
          "minimum": 1
        },
        "data": {
          "anyOf": [
            {
              "type": "string",
              "pattern": "^(https?://[^\\s]+)$"
            },
            {
              "type": "string",
              "pattern": "^[A-Za-z0-9+/]+=*$"
            }
          ]
        },
        "metadata": {
          "type": "object"
        }
      },
      "required": ["id", "dataname", "payload_type", "transport", "encoding", "size", "data"]
    }
  }
}

B. AsyncAPI Specification (NATS)

asyncapi: '2.6.0'
info:
  title: NATSBridge API
  version: '1.0.0'
  description: Cross-platform bi-directional data bridge using NATS
  contact:
    name: NATSBridge Team
    url: https://github.com/your-org/NATSBridge
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
channels:
  /agent/{service}/api/v{version}/{operation}:
    address: /agent/{service}/api/v{version}/{operation}
    parameters:
      service:
        schema:
          type: string
      version:
        schema:
          type: string
          enum: ['v1']
      operation:
        schema:
          type: string
    publish:
      summary: Publish message to NATS
      operationId: publishMessage
      message:
        $ref: '#/components/message'
    subscribe:
      summary: Subscribe to NATS messages
      operationId: subscribeMessage
      message:
        $ref: '#/components/message'
components:
  message:
    payload:
      $ref: '#/components/schemas/Envelope'
  schemas:
    Envelope:
      type: object
      properties:
        correlation_id:
          type: string
          format: uuid
        msg_id:
          type: string
          format: uuid
        timestamp:
          type: string
          format: date-time
        send_to:
          type: string
        msg_purpose:
          type: string
          enum: [ACK, NACK, updateStatus, shutdown, chat, command, event]
        sender_name:
          type: string
        sender_id:
          type: string
          format: uuid
        receiver_name:
          type: string
        receiver_id:
          type: string
          format: uuid
        reply_to:
          type: string
        reply_to_msg_id:
          type: string
        broker_url:
          type: string
        metadata:
          type: object
        payloads:
          type: array
          items:
            $ref: '#/components/schemas/Payload'
      required:
        - correlation_id
        - msg_id
        - timestamp
        - send_to
        - msg_purpose
        - sender_name
        - sender_id
        - receiver_name
        - receiver_id
        - reply_to
        - reply_to_msg_id
        - broker_url
        - payloads
    Payload:
      type: object
      properties:
        id:
          type: string
          format: uuid
        dataname:
          type: string
        payload_type:
          type: string
          enum: [text, dictionary, arrowtable, jsontable, image, audio, video, binary]
        transport:
          type: string
          enum: [direct, link]
        encoding:
          type: string
          enum: [none, base64, json, arrow-ipc]
        size:
          type: integer
          minimum: 1
        data:
          type: string
        metadata:
          type: object
      required:
        - id
        - dataname
        - payload_type
        - transport
        - encoding
        - size
        - data

This specification is versioned and maintained in git alongside the codebase. All implementations must adhere to this specification.