feat(web): route turns through runtime bridge
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"story_id": "story_nana_demo",
|
||||
"current_node": "node_001",
|
||||
"current_branch": "branch_main",
|
||||
"world_flags": {},
|
||||
"relationships": {
|
||||
"nana->player": {
|
||||
"affinity": 48,
|
||||
"trust": 34,
|
||||
"hope": 31,
|
||||
"respect": 45,
|
||||
"intimacy": 26,
|
||||
"attachment": 42
|
||||
}
|
||||
},
|
||||
"relationship_states": [],
|
||||
"promises": [],
|
||||
"knowledge": [
|
||||
{
|
||||
"id": "knowledge_station_clock",
|
||||
"observer": "player",
|
||||
"subject": "old_station_platform",
|
||||
"fact": "站钟停在四点十七分,似乎并非自然损坏。",
|
||||
"certainty": "confirmed",
|
||||
"source": "玩家进入站台时亲眼观察",
|
||||
"learned_at": "node_001",
|
||||
"last_verified_at": "node_001"
|
||||
}
|
||||
],
|
||||
"items": [
|
||||
{
|
||||
"id": "item_flashlight_001",
|
||||
"spec_ref": "nana.item.old_flashlight",
|
||||
"owner": "player",
|
||||
"holder": "player",
|
||||
"placement": "bag",
|
||||
"quantity": 1,
|
||||
"condition": "worn",
|
||||
"state_tags": [],
|
||||
"acquisition": {
|
||||
"mode": "initial",
|
||||
"from": null,
|
||||
"at_node": "node_001"
|
||||
}
|
||||
}
|
||||
],
|
||||
"clocks": [
|
||||
{
|
||||
"id": "clock_dawn",
|
||||
"label": "天亮逼近",
|
||||
"value": 0,
|
||||
"max": 6
|
||||
}
|
||||
],
|
||||
"checks": []
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import initialView from "../../fixtures/player-view/initial.json";
|
||||
import type { PlayerView, TurnRequest, TurnResult } from "@contracts";
|
||||
|
||||
const invokeMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("@tauri-apps/api/core", () => ({
|
||||
invoke: invokeMock
|
||||
}));
|
||||
|
||||
import { submitTurn } from "./bridge";
|
||||
|
||||
const request: TurnRequest = {
|
||||
storyId: initialView.storyId,
|
||||
branchId: initialView.branchId,
|
||||
expectedNodeId: initialView.nodeId,
|
||||
actionId: "action_bridge_test",
|
||||
intent: "continue",
|
||||
input: ""
|
||||
};
|
||||
|
||||
describe("Tauri bridge", () => {
|
||||
beforeEach(() => {
|
||||
invokeMock.mockReset();
|
||||
window.__TAURI_INTERNALS__ = {};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete window.__TAURI_INTERNALS__;
|
||||
});
|
||||
|
||||
it("sends only TurnRequest to the submit_turn command", async () => {
|
||||
const expected: TurnResult = {
|
||||
committedNodeId: "node_002",
|
||||
playerView: {
|
||||
...(initialView as PlayerView),
|
||||
nodeId: "node_002"
|
||||
}
|
||||
};
|
||||
invokeMock.mockResolvedValue(expected);
|
||||
|
||||
await expect(submitTurn(request, initialView as PlayerView)).resolves.toEqual(expected);
|
||||
expect(invokeMock).toHaveBeenCalledWith("submit_turn", { request });
|
||||
});
|
||||
});
|
||||
+19
-1
@@ -1,7 +1,15 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
import initialView from "../../fixtures/player-view/initial.json";
|
||||
import type { AppInfo, DemoPackSummary, PlayerView } from "@contracts";
|
||||
import type {
|
||||
AppInfo,
|
||||
DemoPackSummary,
|
||||
PlayerView,
|
||||
TurnRequest,
|
||||
TurnResult
|
||||
} from "@contracts";
|
||||
|
||||
import { submitDemoTurn } from "./turnAdapter";
|
||||
|
||||
function isTauri(): boolean {
|
||||
return typeof window !== "undefined" && window.__TAURI_INTERNALS__ !== undefined;
|
||||
@@ -40,3 +48,13 @@ export async function getDemoPackSummary(): Promise<DemoPackSummary> {
|
||||
}
|
||||
return invoke<DemoPackSummary>("get_demo_pack_summary");
|
||||
}
|
||||
|
||||
export async function submitTurn(
|
||||
request: TurnRequest,
|
||||
currentView: PlayerView
|
||||
): Promise<TurnResult> {
|
||||
if (!isTauri()) {
|
||||
return submitDemoTurn(request, currentView);
|
||||
}
|
||||
return invoke<TurnResult>("submit_turn", { request });
|
||||
}
|
||||
|
||||
+2
-3
@@ -2,8 +2,7 @@ import { onMounted, ref } from "vue";
|
||||
|
||||
import type { AppInfo, DemoPackSummary, PlayerView, TurnIntent, TurnRequest } from "@contracts";
|
||||
|
||||
import { getAppInfo, getDemoPackSummary, getDemoPlayerView } from "./bridge";
|
||||
import { submitDemoTurn } from "./turnAdapter";
|
||||
import { getAppInfo, getDemoPackSummary, getDemoPlayerView, submitTurn as submitRuntimeTurn } from "./bridge";
|
||||
|
||||
export function useDemo() {
|
||||
const appInfo = ref<AppInfo | null>(null);
|
||||
@@ -51,7 +50,7 @@ export function useDemo() {
|
||||
lastSubmittedIntent.value = intent;
|
||||
|
||||
try {
|
||||
const result = await submitDemoTurn(request, currentView);
|
||||
const result = await submitRuntimeTurn(request, currentView);
|
||||
playerView.value = result.playerView;
|
||||
} catch (reason) {
|
||||
turnError.value = reason instanceof Error ? reason.message : String(reason);
|
||||
|
||||
Reference in New Issue
Block a user