ReadableStream passed to an island component argument becomes an empty object

I am passing ReadableStream to an island component argument becomes an empty object
15 Replies
!Roricchi 2.0『藤田の妻』
@Deno AI Helper
Deno AI Helper
Deno AI Helper7mo ago
I'm sorry, but I wasn't able to find the answer to your question in the official Deno documentation. If you could provide more details or context about your question, I might be able to spot any obvious syntax errors or mistakes. Please share the code or specific issue you're encountering, and I'll do my best to provide advice. Keep in mind that my advice is not based on the Deno documentation, so please double-check the accuracy of any suggestions given.
Deno AI Helper
Deno AI Helper7mo ago
Based on the code snippets you've provided, there seems to be a typo in the Gateway component's props. The prop is named reader, but the error message you're seeing in the browser console is render.read is not a function. This suggests that somewhere in your code, you might be mistakenly referring to render instead of reader. Additionally, the reader.read() call should be inside an asynchronous function or handled with a .catch() to properly deal with potential rejections, but since you haven't asked about error handling, I'll focus on the naming issue. Please ensure that you are passing the reader prop correctly to the Gateway component and that you are not mistakenly using render somewhere else in your code. Also, make sure that the reader object is indeed an instance of a ReadableStreamDefaultReader or has a read method available. Remember, this advice is not based on the Deno documentation, so please double-check the accuracy of the suggestions given.
Deno AI Helper
Deno AI Helper7mo ago
I apologize for the confusion earlier. Looking at your updated code, it seems there is a discrepancy between the prop name in the Gateway component and the prop being passed to it. In the Connect.tsx file, you are passing a prop named readable to the Gateway component:
<Gateway readable={readable} message={message} />
<Gateway readable={readable} message={message} />
However, in the Gateway.tsx file, the component is expecting a prop named reader:
export const Gateway: FunctionComponent<{
reader: ReturnType<Awaited<WebSocketStream['opened']>['readable']['getReader']>
message: Signal<string>
}> = ({ reader, message }) => {
// ...
}
export const Gateway: FunctionComponent<{
reader: ReturnType<Awaited<WebSocketStream['opened']>['readable']['getReader']>
message: Signal<string>
}> = ({ reader, message }) => {
// ...
}
To resolve this issue, you should ensure that the prop names match. You can either change the prop name in the Connect.tsx to reader when passing it to the Gateway component:
<Gateway reader={readable.getReader()} message={message} />
<Gateway reader={readable.getReader()} message={message} />
Or you can adjust the Gateway component to accept a prop named readable:
export const Gateway: FunctionComponent<{
readable: ReadableStream
message: Signal<string>
}> = ({ readable, message }) => {
const reader = readable.getReader();
// ...
}
export const Gateway: FunctionComponent<{
readable: ReadableStream
message: Signal<string>
}> = ({ readable, message }) => {
const reader = readable.getReader();
// ...
}
Additionally, the reader.read() promise should be handled properly with error catching, but since you haven't asked about that, I'll keep the focus on the prop naming issue. Please make sure to align the prop names and their usage across your components. Remember, this advice is not based on the Deno documentation, so please double-check the accuracy of the suggestions given.
Deno AI Helper
Deno AI Helper7mo ago
I wasn't able to find the answer to your question in the official Deno documentation. However, based on the code you've provided, it seems that you have now correctly aligned the prop names between your Connect.tsx and Gateway.tsx files. The reader is being passed to the Gateway component as expected. The issue you're encountering with console.log(reader) logging an empty object in the browser console is a common behavior when logging certain types of objects in JavaScript, especially those with internal properties that are not enumerable or are lazy-loaded, like stream readers. This doesn't necessarily indicate a problem with the code itself. Regarding the error reader.read is not a function, this suggests that the reader object at the time of calling read() is not what you expect it to be. It's possible that the reader object is not being passed correctly as a prop or that it's being modified somewhere else in your code. One thing to note is that the reader object is created outside of the component, which means it's only created once when the module is evaluated. If the WebSocket connection is closed or the reader is released, it won't be recreated when the component re-renders. This could potentially lead to issues if the component expects the reader to be in a certain state. Please double-check that the reader is in the correct state when you're trying to call read() on it. Also, ensure that the reader is not being modified or released elsewhere in your code before the read() method is called. Remember, this advice is not based on the Deno documentation, so please double-check the accuracy of the suggestions given.
Deno AI Helper
Deno AI Helper7mo ago
I wasn't able to find the answer to your question in the official Deno documentation. However, looking at the code you've provided, there seems to be a type error in the Gateway component's props definition. The prop is defined as reader but should be wss based on how you're using it:
export const Gateway: FunctionComponent<{
wss: WebSocketStream;
message: Signal<string>;
}> = ({ wss, message }) => {
// ...
}
export const Gateway: FunctionComponent<{
wss: WebSocketStream;
message: Signal<string>;
}> = ({ wss, message }) => {
// ...
}
Additionally, the error message Uncaught TypeError: Cannot read properties of undefined (reading 'then') suggests that wss.opened is undefined at the time you're trying to access it. This could be due to the WebSocketStream not being in the expected state or the opened property not being available on the wss object. Make sure that the WebSocketStream object is correctly initialized and that the opened property exists and is a promise before you try to call .then() on it. Regarding the console.log(wss) logging an empty object in the browser console, this is a common behavior in browsers when logging objects that contain complex or non-enumerable properties. It doesn't necessarily indicate a problem with the wss object itself. Please double-check the accuracy of the suggestions given, as this advice is not based on the Deno documentation.
Deno AI Helper
Deno AI Helper7mo ago
I wasn't able to find the answer to your question in the official Deno documentation. However, I noticed a syntax error in your Gateway component's props definition. The type for the wss prop is incorrectly closed with a > instead of a }. Here's the corrected prop definition:
export const Gateway: FunctionComponent<{
wss: WebSocketStream;
message: Signal<string>;
}> = ({ wss, message }) => {
// ...
}
export const Gateway: FunctionComponent<{
wss: WebSocketStream;
message: Signal<string>;
}> = ({ wss, message }) => {
// ...
}
Regarding the console.log(wss) issue, logging complex objects like WebSocketStream in the browser console can sometimes display as an empty object due to the way the browser console serializes and displays them. This is a common behavior and not specific to Deno. The error Uncaught TypeError: Cannot read properties of undefined (reading 'then') suggests that wss.opened is not behaving as expected. Since WebSocketStream is an unstable API in Deno, make sure you are using the correct version of Deno where WebSocketStream is supported and that you have enabled the unstable flag if necessary. Please double-check the accuracy of the suggestions given, as this advice is not based on the Deno documentation.
Deno AI Helper
Deno AI Helper7mo ago
I wasn't able to find the answer to your question in the official Deno documentation. However, based on the code snippet you've provided, it seems that you are trying to use a Promise in a way that should be correct, as you are using .then() to handle the resolved value. The error Uncaught TypeError: Cannot read properties of undefined (reading 'then') indicates that conn is not a Promise at the time when you're trying to call .then() on it. This could happen if conn is not being passed correctly to the Gateway component or if it's not initialized as a Promise. As for the console.log(conn) logging an empty object in the browser console, this is a common behavior when logging objects with complex or non-enumerable properties, and it doesn't necessarily indicate a problem with the conn object itself. Please ensure that the conn prop is being passed correctly to the Gateway component and that it is indeed a Promise that resolves to an object with readable, writable, extensions, and protocol properties. Remember, this advice is not based on the Deno documentation, so please double-check the accuracy of the suggestions given.
Deno AI Helper
Deno AI Helper7mo ago
I wasn't able to find the answer to your question in the official Deno documentation. However, looking at the code snippet you've provided, the console.log(conn) behavior you're seeing in the browser console, where it logs an empty object, is typical when logging promises or objects with complex structures. This is due to the way browsers serialize and display them and does not necessarily indicate an issue with the conn object itself. The error Uncaught TypeError: Cannot read properties of undefined (reading 'then') suggests that at the time the code is executed, conn is not recognized as a promise. This could be due to several reasons, such as conn not being properly initialized as a promise or not being passed correctly as a prop. Please ensure that the conn prop is correctly provided to the Gateway component and that it is indeed a promise. If conn is supposed to be a promise that resolves to an object with readable, writable, extensions, and protocol properties, you should verify that it is being set and passed as such. Remember, this advice is not based on the Deno documentation, so please double-check the accuracy of the suggestions given.
!Roricchi 2.0『藤田の妻』
But conn is not recognized as a promise as it gets logged as a Promise {} object in the vs code console as expected but gets logged as an empty object in the browser console.
Deno AI Helper
Deno AI Helper7mo ago
I wasn't able to find the answer to your question in the official Deno documentation. However, the discrepancy you're observing in the logging output between the VS Code console and the browser console is a common behavior due to the different ways these environments handle and display complex objects like promises. In VS Code (and Node.js environments in general), when you log a promise, it often shows Promise { <state> }, where <state> is the current state of the promise (pending, fulfilled, or rejected). In contrast, browsers may log a promise as an empty object or with very little information, which can be confusing but is normal behavior. The error Uncaught TypeError: Cannot read properties of undefined (reading 'then') indicates that at the time the .then() method is being called, conn is undefined. This means that the conn prop may not be passed correctly to the Gateway component, or there is an issue with how the promise is being created or resolved. Please ensure that the conn prop is being passed correctly and that it is initialized properly where you expect it to be a promise. If conn is indeed a promise, this error should not occur as long as conn is defined. Remember, this advice is not based on the Deno documentation, so please double-check the accuracy of the suggestions given.
!Roricchi 2.0『藤田の妻』
console.log('message recived') gets logged in vs code console but not in the browser console, and console.log(conn) too gets logged in vs code console as expected but gets logged as an empty object in the browser console. And in the browser console it also throws Uncaught TypeError: Cannot read properties of undefined (reading 'then')
// islands/Gateway.tsx

/// <reference lib='deno.unstable' />

import type { FunctionComponent } from 'preact'
import type { Signal } from '@preact/signals'

export const Gateway: FunctionComponent<{
conn: Promise<{
readable: ReadableStream<string | Uint8Array>
writable: WritableStream<string | Uint8Array>
extensions: string
protocol: string
}>
message: Signal<string>
}> = ({ conn, message }) => {
console.log(conn) // gets logged in vs code console as expected but gets logged as an empty object in the browser console

conn.then(({ readable }) => { // error, only shown in browser console, Uncaught TypeError: Cannot read properties of undefined (reading 'then')
readable.getReader().read().then((msg) => {
message.value = msg.value as string
console.log('message recieved')
})
})

return (
<div class='max-w-screen-md mx-auto flex flex-col items-center justify-center'>
<div class='flex gap-8 py-6'>
<button>{message}</button>
</div>
</div>
)
}
// islands/Gateway.tsx

/// <reference lib='deno.unstable' />

import type { FunctionComponent } from 'preact'
import type { Signal } from '@preact/signals'

export const Gateway: FunctionComponent<{
conn: Promise<{
readable: ReadableStream<string | Uint8Array>
writable: WritableStream<string | Uint8Array>
extensions: string
protocol: string
}>
message: Signal<string>
}> = ({ conn, message }) => {
console.log(conn) // gets logged in vs code console as expected but gets logged as an empty object in the browser console

conn.then(({ readable }) => { // error, only shown in browser console, Uncaught TypeError: Cannot read properties of undefined (reading 'then')
readable.getReader().read().then((msg) => {
message.value = msg.value as string
console.log('message recieved')
})
})

return (
<div class='max-w-screen-md mx-auto flex flex-col items-center justify-center'>
<div class='flex gap-8 py-6'>
<button>{message}</button>
</div>
</div>
)
}
Deno AI Helper
Deno AI Helper7mo ago
I wasn't able to find the answer to your question in the official Deno documentation. However, based on the code snippet you've provided, if console.log('message received') is not being logged in the browser console but is being logged in the VS Code console, it suggests that the code within the .then() block is not being executed in the browser environment. This could be due to the promise conn not being resolved or an error occurring before reaching that point. The error Uncaught TypeError: Cannot read properties of undefined (reading 'then') indicates that conn is undefined at the time you're trying to call .then() on it in the browser. This could happen if the conn prop is not being passed correctly to the Gateway component or if there's an issue with the promise itself. As for console.log(conn) logging an empty object in the browser console, this is typical behavior when logging promises or objects with complex structures in the browser, as mentioned previously. To address the issue, ensure that: 1. The conn prop is being passed correctly to the Gateway component. 2. The promise conn is properly initialized and is not undefined. 3. There are no errors in the promise chain before the console.log('message received') statement that could prevent it from being reached. Remember, this advice is not based on the Deno documentation, so please double-check the accuracy of the suggestions given.
!Roricchi 2.0『藤田の妻』
Is it because I'm passing functions and WebSocet connections from the server to the browser?
Deno AI Helper
Deno AI Helper7mo ago
Yes, that could be the issue. In a typical setup with Deno and Preact (or any server-side environment with a client-side framework), you cannot pass server-side resources like functions, WebSocket connections, or any other non-serializable objects directly to the browser. The browser environment is separate from the server environment and does not have access to server-side resources unless they are exposed through an API or some form of client-server communication (like WebSockets or HTTP). When you try to pass a server-side resource like a WebSocketStream or a promise that resolves to server-side objects to the client-side code, it won't work because those resources cannot be serialized and sent over the network. The browser will not be able to understand or reconstruct those server-side objects, leading to the issues you're experiencing. Instead, you should establish a WebSocket connection directly from the browser to the server or use an API to communicate between the client and the server. Any server-side logic that involves Deno-specific APIs or resources should be handled on the server, and only data that can be serialized (like JSON) should be sent to the client. Remember, this advice is not based on the Deno documentation, so please double-check the accuracy of the suggestions given.