Skip to content

SocketAdapter TypeScript refactor #926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from

Conversation

drewhoener
Copy link
Contributor

Public API Changes
None

Overview

This PR is a refactor of the SocketAdapter module to TypeScript.
While doing it, I ran into a few curiosities - a good portion of the JSDoc doesn't seem to match up with how the events emitted are actually used in examples.
When reviewing, see SocketAdapter.ts, there's a few FIXME items in particular I'd like to get answers for before merging.

/**
 * FIXME: Need Answers:
 * 1. onopen emits 'connection' event with an object, the typedoc says it's a function, but no examples use it. What is this type?
 * 2. onclose emits 'close' event with an object, the typedoc says it's a function, but no examples use it. What is this type?
 * 3. onerror emits 'error' event with an object, the typedoc says it's a function, but every example uses it like a string. What is this type?
 */

This PR also replaces the old cbor-js dependancy with cbor2 which is much more active; cbor-js hasn't been published in 10 years 0.o.
I don't think it constitutes a breaking change since everything works the same in terms of public API but it's worth calling out as a significant refactor under the hood.
I'm half expecting for you to ask me to move it to a new PR lol, lmk if that's what you want.

Migrating to cbor2 is a good step for a native typescript project. cbor-js didn't have any typedefs beyond encode and decode functions that returned any and didn't document the extra decoding function that was used.
Speaking of which, cbor2 natively supports all the types that were being bootstrapped by the cborTypedArray module, so it's no longer needed.

I did have a bit of an issue when implementing it though, the tests expect BigInt64 and BigUInt64 decode methods to return a plain array of numbers, even when cbor2 correctly decodes it as a BigInt64Array. I added in a shim utility method to support the truncation that was being done before but it struck me as a bit weird...

Other things of note

  • Added in some extensive typing of the RosBridge protocol to support the refactor to the Ros client module later on.
  • Moved GoalStatus to its own typing module for the same reason, it'll help with organization when more Ros2 types need to be added in to support things like the RosAPI messages
  • Added a module for type assertion utils and things of that sort
  • Allow explicit any in eslint, it's helpful for typing the tricker elements when unknown just won't do the trick

As always, please feel free to leave feedback :)

Supports #904

@drewhoener drewhoener changed the title Feature/typescript cbor socket SocketAdapter TypeScript refactor Aug 19, 2025
cbor-js was last published 10+ years ago, stable support is provided by `cbor`, and now the `cbor2` package.

The `cbor2` library is written natively in typescript and supports all the tags we were shimming with cborTypedArrayTags.js. It also supports adding new encoders/decoders later as part of its feature set.

Should be fixed up in the future to address loss of precision expected by old cbor typing functions

Signed-off-by: Drew Hoener <[email protected]>
…not included or bundled in any way

Signed-off-by: Drew Hoener <[email protected]>
@drewhoener drewhoener force-pushed the feature/typescript-cbor-socket branch from 2e6dbf0 to 8004243 Compare August 19, 2025 05:55
export default function SocketAdapter(client: Ros): ISocketAdapter {
let decoder: Nullable<((raw: unknown, outputFunc: (message: object) => void) => void)> = null;
// FIXME: Ros Client types not ready yet
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this chicken-or-the-egg or could we do this first?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More of a chicken-egg thing. If I did the ROS client first, I'd have the same comments in there defering the lint check until the socket types are ready.
FWIW I have the Ros client mostly done, but I figured this would make sense as 2 PRs

@@ -18,6 +18,9 @@ export default tseslint.config(
parserOptions: {
projectService: true,
},
},
rules: {
'@typescript-eslint/no-explicit-any': 0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I'd prefer we hold unknown data in unknown not any, but I won't be super picky about that if you feel strongly since I could see it being a barrier to contribution for people who aren't TypeScript experts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can defer this one, I had it at one point because I had a really uncooperative type but I ended up smoothing it out. It can probably be dropped for now

@@ -235,7 +235,7 @@ export default class Action extends EventEmitter {
id: id,
action: this.name,
values: result,
status: GoalStatus.STATUS_CANCELED,
status: GoalStatus.Canceled,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't changing these member names technically an API-breaking change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think so. GoalStatus was just used in Action and wasn't exported from an index.js file, so it wasn't exposed in the actual "public api". People might have been using it, but it would've been from the dist folder which IMO doesn't count as public API. Happy to discuss it though

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like git mv isn't cooperating here..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want the file history I can do the same dance with the linter/checker we did before?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants