Skip to content

feat(realtime): introduce resultType="json"#180

Merged
efiop merged 2 commits intomainfrom
ruslan/realtime-ws
Jan 8, 2026
Merged

feat(realtime): introduce resultType="json"#180
efiop merged 2 commits intomainfrom
ruslan/realtime-ws

Conversation

@efiop
Copy link
Copy Markdown
Contributor

@efiop efiop commented Jan 8, 2026

Alternative to #178

@efiop efiop force-pushed the ruslan/realtime-ws branch 4 times, most recently from feae3ba to 2a7c9c1 Compare January 8, 2026 18:51
@efiop efiop force-pushed the ruslan/realtime-ws branch from 2a7c9c1 to 5ec7a4f Compare January 8, 2026 19:06
@efiop efiop marked this pull request as ready for review January 8, 2026 19:11
@efiop efiop requested a review from drochetti January 8, 2026 19:12
@efiop
Copy link
Copy Markdown
Contributor Author

efiop commented Jan 8, 2026

I guess we could also introduce just raw for cases where you expect binary data to be sent over too, so your handler could deal with any serialization/etc on itsown.

Let me add that too...

Or maybe just do it as a handler option, hm...

@efiop
Copy link
Copy Markdown
Contributor Author

efiop commented Jan 8, 2026

introduced decodeMessage, encodeMessage, feels more appropriate and natural. Open to feedback.

@efiop
Copy link
Copy Markdown
Contributor Author

efiop commented Jan 8, 2026

So like for json:

import { createRealtimeClient, createConfig } from "@fal-ai/client";

const jsonCodec = {
  encodeMessage: (input: any) =>
    typeof input === "string" ? input : JSON.stringify(input),
  decodeMessage: async (data: any) => {
    const toText = async () => {
      if (typeof data === "string") return data;
      if (data instanceof Uint8Array) return new TextDecoder().decode(data);
      if (data instanceof ArrayBuffer)
        return new TextDecoder().decode(new Uint8Array(data));
      if (data instanceof Blob)
        return new TextDecoder().decode(new Uint8Array(await data.arrayBuffer()));
      return String(data);
    };
    return JSON.parse(await toText());
  },
};

const client = createRealtimeClient({
  config: createConfig({ credentials: process.env.FAL_KEY!, fetch }),
});

const conn = client.connect("your-app-id", {
  ...jsonCodec,
  onResult: (msg) => console.log("result", msg),
  onError: (err) => console.error("error", err),
});

// send plain JS objects; will be JSON-stringified
conn.send({ prompt: "hello json" });
// later
// conn.close();

and just to spice it up, say for protobuf (no need for protobuf, purely illustrative):

import { createRealtimeClient, createConfig } from "@fal-ai/client";
import { MyMessage } from "./generated/my_message"; // your protobufjs static module

const protobufCodec = {
  encodeMessage: (input: any) => {
    // expects input already shaped like MyMessage
    return MyMessage.encode(MyMessage.create(input)).finish(); // Uint8Array
  },
  decodeMessage: async (data: any) => {
    const toBytes = async () => {
      if (data instanceof Uint8Array) return data;
      if (data instanceof ArrayBuffer) return new Uint8Array(data);
      if (data instanceof Blob) return new Uint8Array(await data.arrayBuffer());
      throw new Error("Unsupported payload for protobuf decode");
    };
    return MyMessage.decode(await toBytes());
  },
};

const client = createRealtimeClient({
  config: createConfig({ credentials: process.env.FAL_KEY!, fetch }),
});

const conn = client.connect("your-app-id", {
  ...protobufCodec,
  onResult: (msg) => {
    // msg is a decoded protobuf message
    console.log("proto result", msg);
  },
  onError: (err) => console.error("proto error", err),
});

// send a protobuf-shaped object
conn.send({ prompt: "hello proto" });
// conn.close();

@efiop efiop force-pushed the ruslan/realtime-ws branch from 43db98b to 164ac55 Compare January 8, 2026 20:57
@efiop efiop merged commit dd68d62 into main Jan 8, 2026
1 check passed
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