Stream Objects

Use StreamObjects when a client needs synchronized awareness of Objects in real time. The stream can send an initial snapshot for matching non-deleted Objects and then emit lifecycle updates as Objects are created, updated, deleted, or heartbeat messages are sent.

StreamObjects is a server-streaming RPC and is not available through standard REST/HTTP. Use one of the SDK clients or another gRPC-capable client.
package main

import (
	"connectrpc.com/connect"
	"context"
	"log"

	wdmsdk "github.com/raft-tech/raft-wdm-sdk-go"
	svc "github.com/raft-tech/raft-wdm-sdk-go/gen/raft/wdm/v1/service"
)

func main() {
	cfg, err := wdmsdk.LoadConfig()
	if err != nil {
		log.Fatal(err)
	}

	client, err := wdmsdk.NewFromConfig(cfg)
	if err != nil {
		log.Fatal(err)
	}

	stream, err := client.ObjectService().StreamObjects(context.Background(), connect.NewRequest(&svc.StreamObjectsRequest{
		Projection:            svc.ObjectProjectionMode_OBJECT_PROJECTION_MODE_MINIMAL,
		StreamMode:            svc.ObjectStreamMode_OBJECT_STREAM_MODE_LIVE_ONLY,
		HeartbeatPeriodMillis: 30000,
	}))
	if err != nil {
		log.Fatal(err)
	}
	defer stream.Close()

	for stream.Receive() {
		event := stream.Msg()
		if event.GetEventType() == svc.ObjectEventType_OBJECT_EVENT_TYPE_HEARTBEAT {
			log.Printf("heartbeat")
			continue
		}

		obj := event.GetObject()
		log.Printf("event: %s object: %s %s", event.GetEventType(), obj.GetId(), obj.GetName())
	}
	if err := stream.Err(); err != nil {
		log.Fatal(err)
	}
}
import com.raft.wdm.Wdm;
import com.raft.wdm.raft.wdm.v1.service.ObjectEventType;
import com.raft.wdm.raft.wdm.v1.service.ObjectProjectionMode;
import com.raft.wdm.raft.wdm.v1.service.ObjectStreamMode;
import com.raft.wdm.raft.wdm.v1.service.StreamObjectsRequest;
import com.raft.wdm.raft.wdm.v1.service.StreamObjectsResponse;
import com.raft.wdm.v1.WdmV1Client;

public final class StreamObjectsExample {
  public static void main(String[] args) {
    var options = Wdm.toOptions(Wdm.loadConfig(null, null));

    try (var client = WdmV1Client.create(options)) {
      var req = StreamObjectsRequest.newBuilder()
          .setProjection(ObjectProjectionMode.OBJECT_PROJECTION_MODE_MINIMAL)
          .setStreamMode(ObjectStreamMode.OBJECT_STREAM_MODE_LIVE_ONLY)
          .setHeartbeatPeriodMillis(30000)
          .build();

      try (var stream = client.getObjectServiceBlocking().streamObjects(req)) {
        for (StreamObjectsResponse event : stream) {
          if (event.getEventType() == ObjectEventType.OBJECT_EVENT_TYPE_HEARTBEAT) {
            System.out.println("heartbeat");
            continue;
          }

          var object = event.getObject();
          System.out.printf("event: %s object: %s %s%n",
              event.getEventType(), object.getId(), object.getName());
        }
      }
    }
  }
}
import asyncio

from raft.wdm.v1.service import object_service_pb2

import raft_wdm_sdk


async def main() -> None:
    async with raft_wdm_sdk.Client.from_config(raft_wdm_sdk.load_config()) as client:
        stream = await client.object_service.stream_objects(
            object_service_pb2.StreamObjectsRequest(
                projection=object_service_pb2.OBJECT_PROJECTION_MODE_MINIMAL,
                stream_mode=object_service_pb2.OBJECT_STREAM_MODE_LIVE_ONLY,
                heartbeat_period_millis=30000,
            ),
        )

        async for event in stream:
            if event.event_type == object_service_pb2.OBJECT_EVENT_TYPE_HEARTBEAT:
                print("heartbeat")
                continue

            print(f"event: {event.event_type} object: {event.object.id} {event.object.name}")


asyncio.run(main())
import { create } from "@bufbuild/protobuf";
import { createClient, fromNodeConfig, loadConfig } from "@raft-tech/raft-wdm-sdk-typescript";
import {
  ObjectEventType,
  ObjectProjectionMode,
  ObjectStreamMode,
  StreamObjectsRequestSchema,
} from "@raft-tech/raft-wdm-sdk-typescript/gen/raft/wdm/v1/service/object_service_pb.js";

const client = createClient(...fromNodeConfig(loadConfig()));

const stream = client.objectService.streamObjects(
  create(StreamObjectsRequestSchema, {
    projection: ObjectProjectionMode.MINIMAL,
    streamMode: ObjectStreamMode.LIVE_ONLY,
    heartbeatPeriodMillis: 30000,
  }),
);

for await (const event of stream) {
  if (event.eventType === ObjectEventType.HEARTBEAT) {
    console.log("heartbeat");
    continue;
  }

  console.log(
    `event: ${ObjectEventType[event.eventType]} object: ${event.object?.id} ${event.object?.name}`,
  );
}

Request Shape

A request with no filter streams all Objects. Set streamMode to choose whether the stream includes initial state, live updates, or both. Set projection or fieldMask when the consumer does not need the full Object payload.

{
  "projection": "OBJECT_PROJECTION_MODE_MINIMAL",
  "streamMode": "OBJECT_STREAM_MODE_LIVE_ONLY",
  "heartbeatPeriodMillis": 30000
}

The full contract is defined in the WDM protobuf spec. In the WDM distribution, see raft/wdm/v1/service/object_service.proto for StreamObjectsRequest, StreamObjectsResponse, stream modes, event types, and projection options. See raft/wdm/v1/service/query.proto for ObjectStreamFilter.

Stream Behavior

  • OBJECT_STREAM_MODE_UNSPECIFIED sends initial matching Objects and then continues with live updates.

  • OBJECT_STREAM_MODE_INITIAL_ONLY sends the initial snapshot and closes the stream.

  • OBJECT_STREAM_MODE_LIVE_ONLY skips initial state and emits only changes that happen after subscription.

Each message the client receives is a StreamObjectsResponse. That response carries an eventType and, except for heartbeat messages, the Object associated with the event. The examples above read eventType inside the stream loop to decide whether to handle an Object update or ignore a heartbeat.

{
  "eventType": "OBJECT_EVENT_TYPE_UPDATED",
  "object": {
    "id": "link16-track-47210",
    "name": "TRACK-47210",
    "status": "OBJECT_STATUS_ACTIVE"
  },
  "timestamp": "2026-05-27T21:31:04Z"
}
  • OBJECT_EVENT_TYPE_INITIAL means the Object existed when the stream was established.

  • OBJECT_EVENT_TYPE_CREATED, OBJECT_EVENT_TYPE_UPDATED, and OBJECT_EVENT_TYPE_DELETED describe live lifecycle changes.

  • OBJECT_EVENT_TYPE_HEARTBEAT is a keepalive message when heartbeat is configured.