feat(app): define trusted rewind branch flow
This commit is contained in:
+47
-1
@@ -1,4 +1,11 @@
|
||||
import type { PlayerView, PresentationBeat, TurnRequest, TurnResult } from "@contracts";
|
||||
import type {
|
||||
ForkBranchRequest,
|
||||
ForkBranchResult,
|
||||
PlayerView,
|
||||
PresentationBeat,
|
||||
TurnRequest,
|
||||
TurnResult
|
||||
} from "@contracts";
|
||||
|
||||
const DEMO_LATENCY_MS = 120;
|
||||
|
||||
@@ -95,3 +102,42 @@ export async function submitDemoTurn(
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Browser-only rewind preview. The desktop path performs the durable fork in
|
||||
* SQLite; this adapter mirrors the same DTO boundary without claiming local
|
||||
* persistence.
|
||||
*/
|
||||
export async function forkDemoBranch(
|
||||
request: ForkBranchRequest,
|
||||
currentView: PlayerView
|
||||
): Promise<ForkBranchResult> {
|
||||
await new Promise((resolve) => window.setTimeout(resolve, DEMO_LATENCY_MS));
|
||||
|
||||
if (
|
||||
request.storyId !== currentView.storyId ||
|
||||
request.currentBranchId !== currentView.branchId ||
|
||||
request.expectedCurrentNodeId !== currentView.nodeId
|
||||
) {
|
||||
throw new Error("story branch changed; refresh and retry");
|
||||
}
|
||||
|
||||
const sourceIndex = currentView.history.findIndex((node) => node.id === request.sourceNodeId);
|
||||
if (sourceIndex < 0) throw new Error("selected story node is unavailable");
|
||||
|
||||
const branchId = `branch_${request.actionId.replaceAll(/[^a-zA-Z0-9_.-]/g, "_")}`;
|
||||
const history = currentView.history.slice(0, sourceIndex + 1).map((node) => ({
|
||||
...node,
|
||||
isCurrent: node.id === request.sourceNodeId
|
||||
}));
|
||||
|
||||
return {
|
||||
branchId,
|
||||
playerView: {
|
||||
...currentView,
|
||||
nodeId: request.sourceNodeId,
|
||||
branchId,
|
||||
history
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user