feat(platform): serve Chat from a JS host as an optional capability - #400
feat(platform): serve Chat from a JS host as an optional capability#400filvecchiato wants to merge 2 commits into
Conversation
| navigation, | ||
| notifications, | ||
| // ...required groups... | ||
| chat, // optional: leave it out and chat products get `Unsupported` |
There was a problem hiding this comment.
A JS host that serves chat can create rooms, post messages and list rooms, but can never deliver an incoming message. Nothing in a wasm build can publish a chat action: ChatConnection::publish_action is compiled out on wasm, and its only caller lives in the native module, which is also compiled out. So Chat/action_subscribe returns a subscription that yields nothing and never ends, which a product cannot tell apart from a quiet room. Could you say here that JS-host chat is outbound-only for now, and open a follow-up issue for the inbound path. Custom-message rendering is native-only too.
| .subscribe_rooms(&self.product) | ||
| .map(HostChatListSubscribeItem::V1), | ||
| .subscribe_chat_rooms(&self.product) | ||
| .filter_map(|item| async { item.ok().map(HostChatListSubscribeItem::V1) }), |
There was a problem hiding this comment.
You widened subscribe_chat_rooms to yield a Result, but this line drops the error with no log. One failure from the host leaves the product's room list frozen on its last value forever, with nothing recorded anywhere to say why. Please log it before returning None, the way lookup_subscribe does in this same file. Theme::subscribe at let stream = self.platform.subscribe_theme().filter_map(|item| async { drops errors the same way and would benefit from the same line.
| /// so this is never invoked; it throws rather than returning a value the | ||
| /// decoder would misread. | ||
| fn missing_callback(name: &str) -> Function { | ||
| Function::new_no_args(&format!( |
There was a problem hiding this comment.
Function::new_no_args builds a function from a string of source code, the same way eval does. Browsers block that when the page runs under a Content Security Policy that does not allow unsafe-eval, and they can block it while still allowing WebAssembly to run. This line runs at startup for every host that leaves chat out, three times, so the whole host runtime would fail to start, not just chat. Please build the stub as a Rust closure that returns an error instead of from a source string. noop_function just above does the same thing and can move too.
| ) -> BoxStream<'static, Result<HostChatListSubscribeItem, GenericError>>; | ||
| } | ||
|
|
||
| /// Combined platform interface. A host must provide all capability traits. |
There was a problem hiding this comment.
This doc is now wrong. It is copied into the generated TypeScript and lands directly above chat?: ChatPlatform, so a host author reads "must provide all capability traits" over an interface with an optional member. Could you reword it, something like "A host must provide every capability trait listed here. Members marked optional may be omitted; the core answers their product calls with Unsupported. See [OptionalPlatform]." Saying "members marked optional" rather than only naming the Rust trait matters, because OptionalPlatform does not exist on the TypeScript side. I made the edit and reran codegen to confirm it comes through cleanly.
| provider.dispose(); | ||
| }); | ||
|
|
||
| it("reports the chat capability to the worker when the host serves it", async () => { |
There was a problem hiding this comment.
This covers the init message carrying chat: true, but nothing covers the worker acting on it. No test in the package references createWorkerRawCallbacks or startRawSubscription, so the gate that installs or omits chatRawCallbacks, and the new callbacks.subscribeChatRooms?.(...) path, are both untested. Could you add three cases: chat omitted when no capability is reported, chat proxied when it is, and startRawSubscription("subscribeChatRooms", ...) returning undefined when chat is absent.
| writedoc!( | ||
| out, | ||
| r#" | ||
| /// Optional capabilities the main-thread host actually serves. A |
There was a problem hiding this comment.
This emits Rust /// comments into TypeScript. They are legal but invisible: editors do not show them on hover and they will not reach generated docs, which is a shame since this is exactly the text a host author needs. Everything else in these files uses /** ... */, including the /** Whether the host serves this capability. */ line you generate a few lines below. Please emit JSDoc here and at the matching block in emit_raw_callbacks, which starts /// Byte-oriented callback surface the WASM core invokes. Members of an. There is already a render_jsdoc helper in this file.
Closes #383.
OptionalPlatformsuper-trait intruapi-platformlists capabilities a host may omit. Codegen reads it and emitschat?: ChatPlatformonHostCallbacks, optionalRawCallbacksmembers, andget_optional_functionbindings — so omitting chat keepschat_platform: Noneand the existingUnsupportedanswer.initmessage now carries which optional capabilities the main-thread host serves, so the core sees the same set either side of the boundary.ChatPlatformmethods renamed tocreate_chat_room/post_chat_message/subscribe_chat_rooms: the callback namespace is flat, andpostMessagewas ambiguous.subscribe_chat_roomsnow yields aResultlike every other platform stream.