Welcome to Chapter 2! In the previous chapter, Session Data Models, we learned the "vocabulary" (Zod schemas and Types) that our server uses.
Now, we are going to learn how to start a conversation using that vocabulary.
Imagine you want to stay at a secure hotel. You can't just run straight to a room and jump on the bed. You have to go to the front desk first.
Session Initialization is exactly like a hotel check-in:
cwd - current working directory).Without this step, the real-time connection (WebSocket) cannot happen because the server wouldn't know who you are or where you are working.
createDirectConnectSession
We solve this with a specific function located in createDirectConnectSession.ts. Its job is to perform the "HTTP Handshake" before the real work begins.
Let's break down how to implement this function step-by-step.
First, we need to pack our "ID card" into the HTTP headers. We use a standard called "Bearer Token" for authorization.
// Inside createDirectConnectSession function
const headers: Record<string, string> = {
'content-type': 'application/json',
}
// If a password (token) is required, add it here
if (authToken) {
headers['authorization'] = `Bearer ${authToken}`
}
json so the server knows how to read it. If we have a password (authToken), we write it on the outside of the envelope.
Next, we send the request to the server. We use fetch (standard in modern JavaScript/Node) to send a POST request.
// Sending the request to the server
resp = await fetch(`${serverUrl}/sessions`, {
method: 'POST',
headers,
// We send the Current Working Directory (cwd)
body: jsonStringify({
cwd,
// (Optional logic for permissions omitted for brevity)
}),
})
cwd)."Once the server replies, we can't blindly trust it. We need to verify that the "Key Card" works. This is where we use the Zod Schema we defined in Chapter 1.
// Parse the JSON response
const json = await resp.json()
// Validate it against our strict rules
const result = connectResponseSchema().safeParse(json)
if (!result.success) {
throw new DirectConnectError(
`Invalid session response: ${result.error.message}`,
)
}
connectResponseSchema (from Session Data Models) to check: Does this actually contain a Session ID and a WebSocket URL? If not, we throw an error immediately.Before we look at the return values, let's visualize this handshake.
In programming, things often go wrong. The network might be down, or the password might be wrong.
To make debugging easier for beginners, we wrap these issues in a specific error type: DirectConnectError.
// From createDirectConnectSession.ts
export class DirectConnectError extends Error {
constructor(message: string) {
super(message)
this.name = 'DirectConnectError'
}
}
We use this wrapper to catch generic computer errors and turn them into human-readable messages:
// Catching network errors
} catch (err) {
throw new DirectConnectError(
`Failed to connect to server at ${serverUrl}: ${errorMessage(err)}`,
)
}
This ensures that if the user sees a crash, they know exactly why (e.g., "Failed to connect") rather than seeing a confusing generic system code.
If the function succeeds, it returns a DirectConnectConfig. This is your "Key Card." It contains everything the next system needs to start talking in real-time.
Example Output:
return {
config: {
serverUrl: "http://localhost:3000",
sessionId: "sess_abc123",
wsUrl: "ws://localhost:3000/ws/sess_abc123",
authToken: "secret123",
},
workDir: "/Users/dev/my-project",
}
This object is passed directly to the Direct Connect Manager, which handles the actual websocket connection.
In this chapter, we built the "Check-in" mechanism for our server.
DirectConnectError.
Now that we have checked in and have our "Key Card" (the config object), we are ready to go to our room and start working.
Next Chapter: Direct Connect Manager
Generated by Code IQ