Skip to content

Commit c5a676e

Browse files
author
DavidQ
committed
Enforce launch-context reset for workspace shared handoffs; clear stale assets/palettes before new payload hydration
1 parent be3c898 commit c5a676e

2 files changed

Lines changed: 75 additions & 5 deletions

File tree

tools/shared/platformShell.js

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { getToolById, getToolRegistry } from "../toolRegistry.js";
22
import {
3+
clearSharedAssetHandoff,
4+
clearSharedPaletteHandoff,
35
getSharedShellActions,
46
readSharedAssetHandoff,
57
readSharedPaletteHandoff,
@@ -27,6 +29,7 @@ const TOOLS_PLATFORM_LOGGER = new Logger({ channel: "tools.platform", level: "de
2729
const TOOLS_PLATFORM_BOOT_MS = Date.now();
2830
const GAME_ASSET_CATALOG_SCHEMA = "html-js-gaming.game-asset-catalog";
2931
const GAME_ASSET_CATALOG_VERSION = 1;
32+
const WORKSPACE_LAUNCH_SIGNATURE_STORAGE_KEY = "toolboxaid.toolsPlatform.launchSignature";
3033

3134
function getPageMode() {
3235
return document.body.dataset.toolsPlatformPage || "tool";
@@ -99,12 +102,76 @@ function buildWorkspaceHrefFromGameId(gameId) {
99102
: "";
100103
}
101104

105+
function normalizeSamplePresetPath(value) {
106+
return normalizeLocalHref(value, ["/samples/", "/games/"]);
107+
}
108+
109+
function readLaunchPayloadSignature(searchParams) {
110+
if (!(searchParams instanceof URLSearchParams)) {
111+
return "";
112+
}
113+
const gameId = normalizeTextValue(searchParams.get("gameId") || searchParams.get("game"));
114+
const gameHref = normalizeLocalHref(searchParams.get("gameHref"), ["/games/"]);
115+
const samplePresetPath = normalizeSamplePresetPath(searchParams.get("samplePresetPath"));
116+
const parts = [];
117+
if (gameId) {
118+
parts.push(`gameId=${gameId.toLowerCase()}`);
119+
}
120+
if (gameHref) {
121+
parts.push(`gameHref=${gameHref.toLowerCase()}`);
122+
}
123+
if (samplePresetPath) {
124+
parts.push(`samplePresetPath=${samplePresetPath}`);
125+
}
126+
return parts.join("|");
127+
}
128+
129+
function readStoredLaunchSignature() {
130+
if (typeof window === "undefined") {
131+
return "";
132+
}
133+
try {
134+
return normalizeTextValue(window.localStorage.getItem(WORKSPACE_LAUNCH_SIGNATURE_STORAGE_KEY));
135+
} catch {
136+
return "";
137+
}
138+
}
139+
140+
function writeStoredLaunchSignature(signature) {
141+
if (typeof window === "undefined") {
142+
return;
143+
}
144+
try {
145+
if (signature) {
146+
window.localStorage.setItem(WORKSPACE_LAUNCH_SIGNATURE_STORAGE_KEY, signature);
147+
return;
148+
}
149+
window.localStorage.removeItem(WORKSPACE_LAUNCH_SIGNATURE_STORAGE_KEY);
150+
} catch {
151+
// Ignore storage failures and continue.
152+
}
153+
}
154+
155+
function clearSharedBindingsForNewLaunch(signature) {
156+
if (!signature) {
157+
return false;
158+
}
159+
const previous = readStoredLaunchSignature();
160+
if (previous && previous === signature) {
161+
return false;
162+
}
163+
clearSharedAssetHandoff();
164+
clearSharedPaletteHandoff();
165+
writeStoredLaunchSignature(signature);
166+
return true;
167+
}
168+
102169
function readGameLaunchContext() {
103170
if (typeof window === "undefined") {
104171
return null;
105172
}
106173
const searchParams = new URLSearchParams(window.location.search);
107-
const gameId = normalizeTextValue(searchParams.get("gameId"));
174+
const gameId = normalizeTextValue(searchParams.get("gameId") || searchParams.get("game"));
108175
const gameTitle = normalizeTextValue(searchParams.get("gameTitle"));
109176
const gameHref = normalizeLocalHref(searchParams.get("gameHref"), ["/games/"]);
110177
const workspaceHrefParam = normalizeLocalHref(searchParams.get("workspaceHref"), ["/tools/Workspace%20Manager/", "/tools/Workspace Manager/"]);
@@ -1069,10 +1136,12 @@ async function initPlatformShell() {
10691136

10701137
const currentToolId = document.body.dataset.toolId || "";
10711138
const currentTool = currentToolId ? getToolById(currentToolId) : null;
1072-
const launchContext = readGameLaunchContext();
10731139
const searchParams = typeof window !== "undefined"
10741140
? new URLSearchParams(window.location.search)
10751141
: new URLSearchParams();
1142+
const launchSignature = readLaunchPayloadSignature(searchParams);
1143+
const clearedForLaunch = clearSharedBindingsForNewLaunch(launchSignature);
1144+
const launchContext = readGameLaunchContext();
10761145
const launchedFromSamplePreset = searchParams.has("samplePresetPath");
10771146

10781147
if (currentToolId) {
@@ -1115,6 +1184,9 @@ async function initPlatformShell() {
11151184
const hydratedAsset = await hydrateSharedAssetFromGameLaunchContext(catalogContext);
11161185
const hydratedPalette = await hydrateSharedPaletteFromGameLaunchContext(catalogContext);
11171186
renderShell(currentTool);
1187+
if (clearedForLaunch) {
1188+
TOOLS_PLATFORM_LOGGER.debug("cleared shared workspace bindings for new launch payload");
1189+
}
11181190
if (hydratedAsset) {
11191191
TOOLS_PLATFORM_LOGGER.debug("shared asset hydrated from game asset catalog");
11201192
}

tools/shared/projectSystem.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,6 @@ export function createWorkspaceSystemController(options = {}) {
7777
: {};
7878
const launchGameId = safeString(launchContext.gameId, "");
7979
const launchGameTitle = safeString(launchContext.gameTitle, launchGameId);
80-
const launchReturnTo = safeString(launchContext.returnTo, "");
81-
const isGameReturnLaunch = launchReturnTo.startsWith("/games/");
8280
const onChange = typeof options.onChange === "function" ? options.onChange : () => {};
8381
const onStatus = typeof options.onStatus === "function" ? options.onStatus : () => {};
8482
const adapter = () => getProjectAdapter(toolId);
@@ -120,7 +118,7 @@ export function createWorkspaceSystemController(options = {}) {
120118
});
121119

122120
if (launchGameId) {
123-
if (isGameReturnLaunch && !state.launchContextHydrated) {
121+
if (!state.launchContextHydrated) {
124122
clearSharedAssetHandoff();
125123
clearSharedPaletteHandoff();
126124
}

0 commit comments

Comments
 (0)