Skip to content

Commit 299f032

Browse files
author
Delta Team
committed
PR_26171_GAMMA_028: refresh generated artifacts for main
2 parents afcecc7 + a66048f commit 299f032

602 files changed

Lines changed: 28123 additions & 2394 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ GAMEFOUNDRY_DB_BACKUP_DIR=
5050

5151
# Server-only project asset storage configuration.
5252
# Browser uploads must go through the server API and must not receive these secrets.
53+
# Approved GAMEFOUNDRY_STORAGE_PROJECTS_PREFIX values:
54+
# DEV /dev/projects/
55+
# IST /ist/projects/
56+
# UAT /uat/projects/
57+
# PRD /prod/projects/
5358
GAMEFOUNDRY_STORAGE_ENDPOINT=
5459
GAMEFOUNDRY_STORAGE_ACCESS_KEY_ID=
5560

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
# Ignore the NEXT_COMMAND.txt file
1414
NEXT_COMMAND.txt
1515

16-
# Ignore the tests results and temporary files
16+
# Ignore generated dependency, test result, and temporary files
1717
node_modules/
1818
tests/results/
19+
tests/results/**
1920
tmp/test-results/
21+
tmp/test-results/**
2022
tmp/
2123
scripts/untracked/
2224
projects/
@@ -45,3 +47,4 @@ docs/dev/reports/playwright_v8_coverage_report.txt
4547

4648
# Game Foundry Studio project files
4749
assets/*.gfsp
50+
docs_build/dev/ProjectInstructions.zip

account/user-controls-page.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createControlsToolApiRepository } from "../toolbox/controls/controls-api-client.js";
1+
import { createControlsToolApiRepository } from "../assets/js/shared/controls-api-client.js";
22
import { getSessionCurrent } from "../src/api/session-api-client.js";
33
import InputService from "../src/engine/input/InputService.js";
44
import InputCaptureService from "../src/engine/input/InputCaptureService.js";

admin/infrastructure.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ <h2>Admin</h2>
4141
<p>/dev/projects/</p>
4242
<p>/ist/projects/</p>
4343
<p>/uat/projects/</p>
44-
<p>/prd/projects/</p>
44+
<p>/prod/projects/</p>
4545
</div>
4646
</details>
4747
</div>
@@ -81,7 +81,7 @@ <h3 id="admin-infrastructure-image-zoom-title">Game Foundry Infrastructure</h3>
8181
<tr><td>DEV</td><td>/dev/projects/</td><td>Loading</td></tr>
8282
<tr><td>IST</td><td>/ist/projects/</td><td>Loading</td></tr>
8383
<tr><td>UAT</td><td>/uat/projects/</td><td>Loading</td></tr>
84-
<tr><td>PRD</td><td>/prd/projects/</td><td>Loading</td></tr>
84+
<tr><td>PRD</td><td>/prod/projects/</td><td>Loading</td></tr>
8585
</tbody>
8686
</table>
8787
</div>

admin/system-health.html

Lines changed: 259 additions & 21 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
createServerRepositoryClient,
44
readServerToolConstants,
55
requireServerConstant,
6-
} from "../../src/api/server-api-client.js";
6+
} from "../../../src/api/server-api-client.js";
77

88
const constants = readServerToolConstants("assets");
99

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
createServerRepositoryClient,
33
readServerToolConstants,
44
requireServerConstant,
5-
} from "../../src/api/server-api-client.js";
5+
} from "../../../src/api/server-api-client.js";
66

77
const constants = readServerToolConstants("controls");
88

toolbox/game-journey/game-journey-api-client.js renamed to assets/js/shared/game-journey-api-client.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import {
22
createServerRepositoryClient,
33
readServerToolConstants,
44
requireServerConstant,
5-
} from "../../src/api/server-api-client.js";
5+
} from "../../../src/api/server-api-client.js";
66
export {
77
readGameJourneyCompletionMetrics,
88
updateGameJourneyCompletionMetric,
9-
} from "../../src/api/game-journey-completion-api-client.js";
9+
} from "../../../src/api/game-journey-completion-api-client.js";
1010

1111
const constants = readServerToolConstants("game-journey");
1212

assets/js/shared/status.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
export const STATUS_VALUES = Object.freeze(["PASS", "WARN", "FAIL", "PENDING", "INFO", "SKIP"]);
2+
3+
export function statusText(value, fallback = "not available") {
4+
const text = String(value ?? "").trim();
5+
return text || fallback;
6+
}
7+
8+
export function normalizeStatusValue(value, fallback = "PENDING") {
9+
const normalized = String(value || "").trim().toUpperCase();
10+
return STATUS_VALUES.includes(normalized) ? normalized : fallback;
11+
}
12+
13+
export function formatStatusMessage(status, message, options = {}) {
14+
const normalized = normalizeStatusValue(status, options.fallbackStatus || "PENDING");
15+
const resolvedMessage = Object.hasOwn(options, "fallbackMessage")
16+
? statusText(message, options.fallbackMessage)
17+
: String(message);
18+
return `${normalized}: ${resolvedMessage}`;
19+
}
20+
21+
export function formatStatusReason(status, reason, options = {}) {
22+
const normalized = normalizeStatusValue(status, options.fallbackStatus || "PENDING");
23+
return `${normalized}: ${statusText(reason, options.fallbackReason || "Safe server diagnostics did not provide a reason.")}`;
24+
}
25+
26+
export function applyStatusNode(node, status, options = {}) {
27+
if (!node) {
28+
return "";
29+
}
30+
const normalized = normalizeStatusValue(status, options.fallbackStatus || "PENDING");
31+
node.textContent = normalized;
32+
node.dataset.healthStatus = normalized;
33+
if (normalized === "PASS" && !options.reason) {
34+
node.removeAttribute("title");
35+
node.removeAttribute("aria-label");
36+
return normalized;
37+
}
38+
const reason = statusText(options.reason, options.titleFallback || "Safe server diagnostics returned this non-PASS status.");
39+
node.setAttribute("title", `${options.titlePrefix || "Reason: "}${reason}`);
40+
node.setAttribute("aria-label", formatStatusReason(normalized, options.reason, options));
41+
return normalized;
42+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
const TEXT_TO_SPEECH_PROFILE_STORAGE_KEY = "gamefoundry.textToSpeech.profiles.v1";
2+
const TEXT_TO_SPEECH_PROFILE_STORE_VERSION = "tts-profile-store-v1";
3+
4+
const DEFAULT_LANGUAGE = "en-US";
5+
const DEFAULT_PROVIDER_KEY = "browser-speech";
6+
const DEFAULT_VOICE_AGE = "adult";
7+
8+
function clampNumber(value, fallback, min, max) {
9+
const numberValue = Number(value);
10+
if (!Number.isFinite(numberValue)) {
11+
return fallback;
12+
}
13+
return Math.min(max, Math.max(min, numberValue));
14+
}
15+
16+
function normalizedText(value, fallback = "") {
17+
const text = String(value || "").trim();
18+
return text || fallback;
19+
}
20+
21+
function slugFromText(value, fallback = "item") {
22+
return normalizedText(value, fallback)
23+
.toLowerCase()
24+
.replace(/[^a-z0-9]+/g, "-")
25+
.replace(/^-+|-+$/g, "") || fallback;
26+
}
27+
28+
function labelFromSlug(value, fallback = "Neutral") {
29+
return normalizedText(value, fallback)
30+
.replace(/[-_]+/g, " ")
31+
.replace(/\b\w/g, (letter) => letter.toUpperCase());
32+
}
33+
34+
function defaultStorage() {
35+
try {
36+
return typeof window === "undefined" ? null : window.localStorage;
37+
} catch {
38+
return null;
39+
}
40+
}
41+
42+
function storagePayloadProfiles(payload) {
43+
if (Array.isArray(payload)) {
44+
return payload;
45+
}
46+
if (Array.isArray(payload?.profiles)) {
47+
return payload.profiles;
48+
}
49+
return [];
50+
}
51+
52+
function normalizeSavedEmotion(emotion = {}) {
53+
const emotionKey = slugFromText(emotion.emotion || emotion.id || emotion.emotionLabel, "neutral");
54+
const emotionLabel = normalizedText(emotion.emotionLabel || emotion.name, labelFromSlug(emotionKey));
55+
return {
56+
active: emotion.active !== false,
57+
emotion: emotionKey,
58+
emotionLabel,
59+
id: normalizedText(emotion.id, emotionKey),
60+
messagePartsUsageCount: Math.max(0, Number(emotion.messagePartsUsageCount) || 0),
61+
pitch: clampNumber(emotion.pitch, 1, 0.1, 2),
62+
rate: clampNumber(emotion.rate, 1, 0.1, 2),
63+
ssmlLikePreset: normalizedText(emotion.ssmlLikePreset, "normal"),
64+
volume: clampNumber(emotion.volume, 1, 0, 1),
65+
};
66+
}
67+
68+
function normalizeSavedProfile(profile = {}) {
69+
const name = normalizedText(profile.name, "Default Balanced Profile");
70+
const emotions = Array.isArray(profile.emotions) && profile.emotions.length
71+
? profile.emotions.map(normalizeSavedEmotion)
72+
: [normalizeSavedEmotion()];
73+
return {
74+
active: profile.active !== false,
75+
age: normalizedText(profile.age, DEFAULT_VOICE_AGE),
76+
emotions,
77+
gender: normalizedText(profile.gender, "neutral"),
78+
id: normalizedText(profile.id, slugFromText(name, "tts-profile")),
79+
language: normalizedText(profile.language, DEFAULT_LANGUAGE),
80+
messageStudioUsageCount: Math.max(0, Number(profile.messageStudioUsageCount) || 0),
81+
name,
82+
owner: "Audio",
83+
providerKey: normalizedText(profile.providerKey, DEFAULT_PROVIDER_KEY),
84+
voice: normalizedText(profile.voice),
85+
voiceName: normalizedText(profile.voiceName || profile.voice, "Default browser voice"),
86+
};
87+
}
88+
89+
function normalizeSavedTextToSpeechProfiles(profiles = []) {
90+
return Array.isArray(profiles) ? profiles.map(normalizeSavedProfile) : [];
91+
}
92+
93+
function readSavedTextToSpeechProfiles(storage = defaultStorage()) {
94+
if (!storage || typeof storage.getItem !== "function") {
95+
return [];
96+
}
97+
const raw = storage.getItem(TEXT_TO_SPEECH_PROFILE_STORAGE_KEY);
98+
if (!raw) {
99+
return [];
100+
}
101+
let payload;
102+
try {
103+
payload = JSON.parse(raw);
104+
} catch {
105+
throw new Error("Saved Text To Speech profiles could not be read.");
106+
}
107+
return normalizeSavedTextToSpeechProfiles(storagePayloadProfiles(payload));
108+
}
109+
110+
function writeSavedTextToSpeechProfiles(profiles = [], storage = defaultStorage()) {
111+
if (!storage || typeof storage.setItem !== "function") {
112+
return false;
113+
}
114+
const payload = {
115+
profiles: normalizeSavedTextToSpeechProfiles(profiles),
116+
updatedAt: new Date().toISOString(),
117+
version: TEXT_TO_SPEECH_PROFILE_STORE_VERSION,
118+
};
119+
storage.setItem(TEXT_TO_SPEECH_PROFILE_STORAGE_KEY, JSON.stringify(payload));
120+
return true;
121+
}
122+
123+
function textToSpeechProfilesToMessageOptions(profiles = []) {
124+
return normalizeSavedTextToSpeechProfiles(profiles)
125+
.filter((profile) => profile.active !== false)
126+
.map((profile) => ({
127+
active: true,
128+
age: profile.age,
129+
ageFilter: profile.age,
130+
emotionSettings: profile.emotions
131+
.filter((emotion) => emotion.active !== false)
132+
.map((emotion) => ({
133+
active: true,
134+
emotion: emotion.emotion,
135+
emotionLabel: emotion.emotionLabel,
136+
key: emotion.id,
137+
pitch: emotion.pitch,
138+
rate: emotion.rate,
139+
ssmlLikePreset: emotion.ssmlLikePreset,
140+
volume: emotion.volume,
141+
})),
142+
gender: profile.gender,
143+
key: profile.id,
144+
language: profile.language,
145+
name: profile.name,
146+
providerKey: profile.providerKey,
147+
sourceProfileId: profile.id,
148+
voice: profile.voice,
149+
voiceName: profile.voiceName || profile.voice || "Default browser voice",
150+
}));
151+
}
152+
153+
export {
154+
TEXT_TO_SPEECH_PROFILE_STORAGE_KEY,
155+
TEXT_TO_SPEECH_PROFILE_STORE_VERSION,
156+
normalizeSavedTextToSpeechProfiles,
157+
readSavedTextToSpeechProfiles,
158+
textToSpeechProfilesToMessageOptions,
159+
writeSavedTextToSpeechProfiles,
160+
};

0 commit comments

Comments
 (0)