Description
This issue proposes that an effort should be made to re-write the core set of rsocket-js
packages from Flow to TypeScript, with a focus on adopting a "small core" mentality when designing the projects public API.
This issue is to serve as:
- Documentation of the proposal that was discussed and decided upon
- A means of tracking progress towards implementing the proposal
Motivation
TypeScript in Favor of Flow
TypeScript is a proven solution for authoring JavaScript libraries for use in NodeJs and browser environments, and will provide a number of benefits to the project:
- Continued development & support from Microsoft
- Large community adoption
- Easier and more familiar tooling
- Types can be published from source without authoring additional
@types
In addition to the above, in a recent post on the Flow Type blog, the Flow team described a refocusing of the projects priorities towards Facebook's internal needs. This is a signal that Flow may not be a suitable solution for projects outside of Facebook's internal infrastructure and ecosystem.
Small Core
New APIs and paradigms should be introduced to adopt a "small core" mentality, with core rsocket-js
packages providing only the basic building blocks and implementations for the RSocket protocol. APIs should be easily extendable/composable to support additional packages that can later provide functionality outside of implementing the RSocket protocol, for example, an RxJS
interface.
This "small core" approach is intended to assist with maintainability of the project, as well as ease of support for satisfying feature requests through extensions and "addon" packages.
Other RSocket implementations, such as RSocket-Swift, have benefited to a degree from this approach.
Serialization and Encoding
In conformance with the "small core" goal of this initiative, support for payload data encoding should be reduced down to transmitting instances of Buffer
, rather than supporting a wide variety of data
and metadata
payload serialization and encodings. This stance is in contrast to the current support provided by @rsocket
packages, where support for serializing objects to JSON and other formats is provided by interfaces such as JsonSerializer
, and encoding is provided by interfaces such as BufferEncoders
.
Support for user friendly translation of objects and other structures to/from JSON
and other serialization formats can be accomplished via extension packages, rather than as a core feature of rsocket-js
.
Reactive APIs
rsocket-js
has historically leveraged a Reactive Streams implementation (rsocket-flowable) both internally, and as its public API. This implementation has historically been published under @rsocekt/rsocket-flowable
. Moving forward, rsocket-js
will move away from @rsocket/rsocket-flowable
as a key feature of its public API, and instead focus on exposing a core set of Stream APIs that satisfy the core requirements of the RSocket protocol, while also promoting composition and extension with other Reactive Streams implementations, such as RxJS and reactive-streams-js.
Interfaces example:
export interface Cancellable {
cancel(): void;
}
export interface Requestable {
request(requestN: number): void;
}
export interface OnExtensionSubscriber {
onExtension(
extendedType: number,
content: Buffer | null | undefined,
canBeIgnored: boolean
): void;
}
export interface OnNextSubscriber {
onNext(payload: Payload, isComplete: boolean): void;
}
export interface OnTerminalSubscriber {
onError(error: Error): void;
onComplete(): void;
}
The intention of this change is two fold:
- Simplify the internal implementation details of the core
rsocket-js
libraries - Allow for consumers and integrators to easily extend
rsocket-js
with their Reactive Streams implementation of choice
Desired solution
Core RSocket protocol feature support, and APIs implementations needed:
-
RSocketConnector
API - Transports
- TCP Client
- TCP Server
- WebSocket Client
- Browser compatibility
- Non-browser compatibility
- WebSocket Server
- Request Operators
- Fire and Forget
- Request Response
- Request Stream
- Request Channel
- Metadata Push
- Fragmentation
- Keepalive
- Composite Metadata
- Routing
- AuthMetadata
- Resumption
- Leasing
- Requester side leasing
- Responder side leasing
- Requester Side Acceptor
- Encoding/Decoding API
- Loadbalancing
- Improved browser environment support
- Clear support/guidance on Buffer API in Browser environments
TODO: complete list of necessary core protocol features
Considered alternatives
N/A
Additional context
Major Version Change
Because of the breaking API changes that this effort will introduce, the version of all @rsocket
scoped packages who's APIs are modified will be incremented to an initial major version release of 1.0
.
Issues & pull requests related to this work should be/are tagged with the 1.0
tag.
Work in progress
Work for this effort is ongoing in the dev
branch.
API Example
const connector = new RSocketConnector({
transport: new TcpClientTransport({
connectionOptions: {
host: "127.0.0.1",
port: 9090,
},
}),
});
const rsocket = await connector.bind();
await new Promise((resolve, reject) =>
rsocket.requestResponse(
{
data: Buffer.from("Hello World"),
},
{
onError: (e) => reject(e),
onNext: (payload, isComplete) => {
console.log(
`payload[data: ${payload.data}; metadata: ${payload.metadata}]|${isComplete}`
);
resolve(payload);
},
onComplete: () => { },
onExtension: () => { },
cancel: () => { },
request: () => { },
}
)
);