# Request/Response Flow

Positron’s asynchronous `Window.request()` API makes it easy to build Promise-based request/response cycles between your Node.js application and your native Swift or C# extensions.

Because native extensions are executed via a `handle()` function that returns `Void`, you cannot `return` a value synchronously. Instead, you use the IPC WebSocket client to emit a response back to Node.js.

### How `Window.request()` Works

The `Window.request(command, replyChannel, ...args)` method does the following:

1. Temporarily registers an IPC handler in Node.js listening for the `replyChannel`.
2. Sends the `command` (and any `args`) down to the native runtime via the standard IPC pipeline.
3. Returns a `Promise` that resolves automatically when the native runtime emits an event matching the `replyChannel`.
4. Times out after 5 seconds if no response is received.

### Package.json

Define the config in your module's `package.json`

```json
{
  "name": "positron-my-ext",
  "version": "1.0.0",
  "positron": {
    "command": "my-ext",
    "className": "MyExtension",
    "platforms": {
      "darwin": "mac/ext.swift",
      "win32": "win/ext.cs"
    }
  }
}
```

### Node.js Implementation

On the Node side, invoke your native extension using `Window.request()`.

> **Best Practice:** Always include the `window.id` in your reply channel string and ensure it contains the phrase `-reply-` or `-result-`. Positron’s internal router automatically intercepts native events containing `-reply-` or `-result-` and routes them directly to IPC listeners.

```javascript
const { Window } = require('positron.js');

const win = new Window();

win.on('ready', async () => {
    try {
        // We define a unique reply channel for this request.
        const replyChannel = `my-ext-reply-${win.id}`;
        
        // request() resolves when the native layer responds on 'my-ext-reply-X'
        const response = await win.request('my-ext-command', replyChannel, "some-arg");
        
        console.log("Extension returned:", response);
    } catch (err) {
        console.error("Extension request failed:", err);
    }
});
```

### macOS (Swift) Implementation

In your native extension, intercept the command, process the arguments, and send back an `IPCResponse`.

Because you used a reply channel with `-reply-` in the name, you can set the `event` field of the `IPCResponse` directly to the reply channel string. Positron will automatically extract the `data` dictionary and pass it to your Node.js Promise.

```swift
import Foundation

public class MyExtension {

    static func handle(windowId: Int, args: [String]) {
        // 1. Process your arguments
        let firstArg = args.first ?? "unknown"
        print("Running native task with arg: \(firstArg)")
        
        // 2. Perform native work...
        let resultValue = "42"
        
        // The last arg is always the reply channel if called with Window.request() in v1.0.1+
        let replyChannel = args.last ?? "my-ext-reply-\(windowId)"
        
        // 3. Construct the response
        // The event name MUST match the replyChannel you awaited in Node.js
         let response = IPCResponse(
            windowId: windowId,
            event: replyChannel,
            data: [
                "result": resultValue
            ]
        )
        
        // 4. Send the response over the IPC WebSocket
        AppDelegate.shared?.ipcClient.send(response)
    }
}
```

### Windows (C#) Implementation

The pattern is identical on Windows. Use the globally available `IPCClient` to fire the response payload back over the socket.

{% code lineNumbers="true" %}

```csharp
using System.Collections.Generic;

namespace PositronWindows 
{
    public class MyExtension 
    {
        
        public static void Handle(int windowId, List<string> args) 
        {
            // 1. Process your arguments
            string firstArg = args.Count > 0 ? args[0] : "unknown";
            
            // 2. Perform native work...
            string resultValue = "42";
            
            // The last arg is always the reply channel if called with Window.request() in v1.0.1+
            string replyChannel = args[^1]
            
            // 3. Construct the response
            // The event name MUST match the replyChannel you awaited in Node.js
            var response = new IPCResponse
            {
                windowId = windowId,
                @event = replyChannel,
                data = new Dictionary<string, string>
                {
                    { "status", "success" },
                    { "value", resultValue }
                }
            };
            
            // 4. Send the response over the IPC WebSocket
            App._ipcClient.Send(response);
        }
    }
}
```

{% endcode %}

### Passing the Reply Channel Dynamically

If you want to avoid hardcoding `"my-ext-reply-\(windowId)"` in your native code, the reply channel is automatically passed as the **last arg** if invoked with `Window.request()`, you read it from the `args` array in Swift/C#, and use it to format your `IPCResponse` dynamically. This is useful for extensions that handle many parallel requests and need unique UUID-based reply channels to avoid collisions.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://positronjs.gitbook.io/v1/extensions/create/flow.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
