mirror of
https://github.com/bdnugget/rs-sdk.git
synced 2026-11-07 09:07:30 +00:00
execute_code - Cancellation now reaches inside the SDK via an AsyncLocalStorage scope: timeout, MCP cancel, or a newer call rejects pending waits and blocks further action packets, including those inside walkTo(). - One execution per bot: a new call supersedes the running one and starts once it has unwound; disconnect_bot does the same. - Cancelled user code parks on bot/sdk calls instead of throwing, so a catch-all loop can't spin and starve the server. - Console capture is routed per execution, so concurrent bots no longer clobber each other's output; leftover logs go to stderr. - Stale world state warns and still runs, so a stale client can be diagnosed. - Credentials are redacted from logs, results and launch messages. SDK - bot.mineRock() waits for ore plus Mining XP; interactLoc docs note that success can mean the action only started. - walkTo() takes options.timeout (default 120s), refuses stale state, and reports the real last position. - runScript uses the same cancellation scope for timeouts and signals. Docs trimmed of duplicated or stale execute_code text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
89 lines
3.2 KiB
TypeScript
89 lines
3.2 KiB
TypeScript
import { describe, expect, test } from 'bun:test';
|
|
import { BotSDK } from '../index';
|
|
import type { ActionResult } from '../types';
|
|
|
|
/**
|
|
* Build an SDK that looks connected but whose socket swallows everything, so a
|
|
* dispatch never gets a result back.
|
|
*/
|
|
function stubSdk(actionTimeout: number) {
|
|
const sdk = Object.create(BotSDK.prototype) as BotSDK;
|
|
const sent: any[] = [];
|
|
(sdk as any).config = { actionTimeout, botUsername: 'tester' };
|
|
(sdk as any).connectionState = 'connected';
|
|
(sdk as any).pendingActions = new Map();
|
|
(sdk as any).ws = { readyState: WebSocket.OPEN };
|
|
(sdk as any).send = (msg: any) => sent.push(msg);
|
|
return { sdk, sent, pending: (sdk as any).pendingActions as Map<string, any> };
|
|
}
|
|
|
|
function dispatch(sdk: BotSDK): Promise<ActionResult> {
|
|
return (sdk as any).sendAction({ type: 'walkTo', x: 0, z: 0, running: true, reason: 'SDK' });
|
|
}
|
|
|
|
describe('BotSDK.sendAction dispatch failures', () => {
|
|
test('cleans pending dispatches when the socket write throws synchronously', async () => {
|
|
const { sdk, pending } = stubSdk(5000);
|
|
(sdk as any).send = () => { throw new Error('Socket write failed'); };
|
|
expect(await dispatch(sdk)).toMatchObject({ success: false, reason: 'error', message: 'Socket write failed' });
|
|
expect(pending.size).toBe(0);
|
|
});
|
|
|
|
test('reports a timeout instead of throwing', async () => {
|
|
const { sdk, sent, pending } = stubSdk(20);
|
|
|
|
const result = await dispatch(sdk);
|
|
|
|
expect(sent).toHaveLength(1);
|
|
expect(result.success).toBe(false);
|
|
expect(result.reason).toBe('timeout');
|
|
expect(result.phase).toBe('dispatch');
|
|
expect(result.message).toContain('walkTo');
|
|
expect(pending.size).toBe(0);
|
|
});
|
|
|
|
test('reports a mid-flight disconnect instead of throwing', async () => {
|
|
const { sdk, pending } = stubSdk(5000);
|
|
|
|
const promise = dispatch(sdk);
|
|
const entry = [...pending.values()][0]!;
|
|
clearTimeout(entry.timeout);
|
|
entry.reject(new Error('Connection closed'));
|
|
|
|
const result = await promise;
|
|
expect(result.success).toBe(false);
|
|
expect(result.message).toBe('Connection closed');
|
|
});
|
|
|
|
test('reports a gateway error instead of throwing', async () => {
|
|
const { sdk, sent } = stubSdk(5000);
|
|
|
|
const promise = dispatch(sdk);
|
|
(sdk as any).handleMessage(JSON.stringify({
|
|
type: 'sdk_error',
|
|
actionId: sent[0].actionId,
|
|
error: 'Bot not connected to gateway'
|
|
}));
|
|
|
|
const result = await promise;
|
|
expect(result.success).toBe(false);
|
|
expect(result.reason).toBe('error');
|
|
expect(result.message).toBe('Bot not connected to gateway');
|
|
});
|
|
|
|
test('still resolves normally when a result arrives', async () => {
|
|
const { sdk, sent, pending } = stubSdk(5000);
|
|
|
|
const promise = dispatch(sdk);
|
|
const actionId = sent[0].actionId;
|
|
(sdk as any).handleMessage(JSON.stringify({
|
|
type: 'sdk_action_result',
|
|
actionId,
|
|
result: { success: true, message: 'Walking' }
|
|
}));
|
|
|
|
expect(await promise).toEqual({ success: true, message: 'Walking' });
|
|
expect(pending.size).toBe(0);
|
|
});
|
|
});
|