@xudesheng/alwayson-js-codec
v0.1.4
Published
Minimal JS/WASM-focused ThingWorx AlwaysOn codec
Readme
alwayson-js-codec
alwayson-js-codec is a small, publishable AlwaysOn protocol codec for JavaScript and WebAssembly.
This repository exists because we want a public, focused codec library that can power a lightweight ThingWorx AlwaysOn client in ai-parler without exposing or depending on the author's broader private Rust prototype. The long-term goal is:
- keep this repo narrowly scoped to protocol encoding/decoding
- keep transport/session logic in JavaScript, close to the widget that uses it
- make it obvious how
ai-parlercan build a Parler-specific AlwaysOn client on top
Why This Repo Exists
The original exploration happened in a private Rust repository that implements a fuller AlwaysOn codec. That private work is the historical source of truth for the ideas here, but this repo is intended to be:
- safe to publish
- small enough to understand quickly
- intentionally designed for JS/WASM consumption
This repo is not trying to become a second tw-javascript-sdk.
Scope
This crate is responsible for:
- binary encoding/decoding of core AlwaysOn messages
- message header handling
- auth and bind message bodies
- a JS/WASM-friendly API surface
- documentation that explains how to pair this codec with a thin browser transport/session shell
This crate is not responsible for:
- WebSocket lifecycle management
- reconnect logic
- heartbeat scheduling
- callback registries
- widget UI state
- Parler business logic
Current Status
This is the initial bootstrap of the public-facing crate.
Implemented now:
- core message header
- auth body codec
- bind body codec
- unbind support using the same body shape as bind, but with explicit
unbindsemantics in the public API - request / response body codec
- common ThingWorx response/error status codes beyond plain
Success - minimal
InfoTable/DataShape/ primitive support for service calls - minimal top-level message builders
- a framed
parse_inbound_message(...)helper for browser shells - multipart chunk parsing, splitting, and merging aligned with
tw-javascript-sdk - outbound multipart helpers that can emit ready-to-send on-wire chunk bytes
- first-pass
wasm-bindgenexports - fixed interop fixtures for auth, bind, and error response decoding
Planned next:
- JS wrapper ergonomics
- examples showing integration from
ai-parler
Relationship To Other Repos
../rust/alwayson-codecPrivate source of prior exploration. This repo intentionally copies only the minimum necessary code and reshapes it for public JS/WASM use.../parlerHome ofai-parler, where the browser transport/session shell should live.../twx-agent-extensionThe ThingWorx server-side extension whose AlwaysOn usage drove this work.
Design Direction
The intended architecture is:
alwayson-js-codechandles protocol bytes and message objects.ai-parlerprovides a thin browser transport/session shell around nativeWebSocket.- That shell implements only the minimum client behavior needed by Parler:
- open socket
- send auth
- send bind
- maintain
requestId,sessionId,endpointId - dispatch incoming requests
- respond to
GetMetadata,SynchronizeModelState, andReceiveMessage
The current crate already includes a one-shot inbound parser so the JS shell does not need to hand-roll header/body offset math before dispatching service requests or responses.
That parser assumes the input slice starts at a message boundary. If a browser transport sees coalesced or partial binary frames, it should buffer data in JavaScript, call parse_inbound_message(...) only at offset 0, then advance by consumed.
For the wider Parler naming context, see the sibling server-side design note in ../twx-agent-extension/docs/parler-gateway-design.md, especially the gateway-vs-conversation discussion around section 2.2.
For auth-like inbound messages, parse_inbound_message(...) now distinguishes:
kind: "auth"whenheader.codeisAuthkind: "clear_auth"whenheader.codeisClearAuth
For build_response_message(...), the status_code argument is the raw AlwaysOn response opcode. Common values:
| Code | Name |
|------|------|
| 0x40 | Success |
| 0x80 | BadRequest |
| 0x84 | NotFound |
| 0x85 | MethodNotAllowed |
| 0xA0 | InternalError |
| 0xA3 | ServiceUnavailable |
| 0xA5 | NotImplemented |
Multipart helpers now available in the WASM surface:
parse_multipart_chunk(...)split_multipart_message(...)encode_multipart_chunk(...)split_multipart_message_bytes(...)merge_multipart_chunks_bytes(...)merge_multipart_chunks_json(...)
For outbound multipart sends, the JS shell can now choose either path:
- call
split_multipart_message(...), then encode individual JSON chunks withencode_multipart_chunk(...) - or call
split_multipart_message_bytes(...)to get ready-to-send on-wire chunk frames directly
Multipart compatibility note:
alwayson-js-codecintentionally follows thetw-javascript-sdkmultipart family for browser parity.- Historical ThingWorx clients are not perfectly uniform here: the C SDK and the author's earlier private Rust prototype use a different on-wire multipart shape in some cases.
- For Parler and other browser-side consumers, this crate treats JS/browser parity as the compatibility target rather than trying to produce both multipart wire layouts at once.
Blob note:
TwPrim::Blobin this crate is rawu32 length + bytes.tw-javascript-sdkhigher-level Blob helpers commonly use base64 strings.- If the JS shell needs SDK-style Blob behavior, convert base64 at the shell boundary before calling this codec.
Repository Guide
- Read docs/spec.md first.
- Read AGENTS.md if you are using an AI coding tool.
- Keep this repo codec-focused. Do not move browser runtime logic into Rust unless there is a very strong reason.
Polite Note To Future Maintainers
Thanks for taking a look at this project.
If you are here because you want a tiny, understandable AlwaysOn codec that is friendlier to JS/WASM than a full client SDK, you are in the right place. If you need a complete transport/session runtime, this repo should help you build one, but it should not quietly turn into one itself.
