SoulFire TypeScript SDK 2.10.3
    Preparing search index...

    Connection and bot lifecycle

    Choose the entry point for your runtime:

    Import Use
    @soulfiremc/sdk/node Node.js connections, managed installation, and createBot
    @soulfiremc/sdk/bun Bun connections, managed installation, and createBot
    @soulfiremc/sdk/browser Browser connections to an existing SoulFire server
    @soulfiremc/sdk Universal connection API with an existing transport or fetch implementation

    SoulFire.connect takes a SoulFire gRPC-Web URL, such as http://localhost:38765. Bot provisioning takes a Minecraft address, such as localhost:25565. These addresses point to different services.

    • SoulFire.createBot from /node or /bun installs a local server and returns a ready bot.
    • SoulFire.install installs once so several bots can share one managed server.
    • SoulFire.connect connects to an existing server and checks compatibility.
    • client.instance(id).bot(id) creates handles for existing UUIDs without a request or readiness wait.

    Named provisioning reuses instances and accounts. It reports conflicting configuration rather than silently replacing it. Instances and accounts persist when the connection scope closes.

    Use these imports for the examples:

    import { Effect, Stream } from "effect";
    import { SoulFire } from "@soulfiremc/sdk/node";

    SDK operations are lazy. Calling a method creates an Effect; yield* executes it within a workflow. Run the complete workflow at the application boundary.

    await Effect.runPromise(collectWithClient);
    

    The following workflow connects, provisions a ready bot, and collects 16 log blocks:

    export const collectWithClient = Effect.scoped(
    Effect.gen(function* () {
    const client = yield* SoulFire.connect({
    baseUrl: "http://localhost:38765",
    token: () => process.env.SOULFIRE_TOKEN,
    });
    const instance = yield* client.getOrCreateInstance("reference-example", {
    server: "localhost:25565",
    });
    const bot = yield* instance.getOrCreateBot("Builder", {
    username: "Builder",
    readyTimeoutMs: 30_000,
    });
    const result = yield* bot.collect("#minecraft:logs", { count: 16 });
    yield* Effect.logInfo(result);
    }),
    );

    The Minecraft server must accept offline accounts for this example. Set SOULFIRE_TOKEN if the SoulFire server requires authentication.

    bot.connect() starts a stopped bot and waits for its initial player snapshot. It also attaches the session that supplies bot.state. readyTimeoutMs defaults to 30,000 milliseconds and must be positive and finite.

    The scope closes observation and stops a bot only if the SDK started it. A previously running bot stays running. Managed installation also stops its local SoulFire process when the outer scope closes. Keep all bot work inside that scope; returning a handle from a closed scope does not keep resources alive.

    bot.start() changes desired state without a readiness wait or cleanup ownership. bot.waitForOnline() waits for live state without attaching bot.state. bot.observe() returns a separate session unless it can reuse one already attached. Read that session's state when you open observation separately.

    Limit Unit Controls
    readyTimeoutMs Milliseconds Bot startup and initial player snapshot
    startupTimeoutMs Milliseconds Managed SoulFire process startup
    defaultTimeoutMs or call.timeoutMs Milliseconds RPC transport timeout
    Task deadline Absolute Date Server task execution

    A shorter RPC timeout can fail before the readiness deadline. A task deadline is independent of the client request timeout.

    Expected SDK failures use the Effect error channel. Connection failures use SoulFireConnectionError; operation errors include RPC, readiness, action, and task failures. Use Effect.catchTag to recover from a specific error. Effect.runPromise rejects when a workflow fails without recovery.

    Do not retry every action automatically. Retrying a completed mutation can repeat its side effects. For task submission retries, use a stable idempotency key for the same job. A new intended job needs a new key.

    For exclusive action control, use bot.acquireControlScoped(). The scope releases the lease, but it does not renew it. Call lease.renew() before expiry for longer work.

    Continue with task execution, the TypeScript tutorial, or complete SDK recipes.