Skip to content

Commit c965a7a

Browse files
committed
Activate DEV Supabase Auth provider wiring without product data migration - PR_26166_141-supabase-dev-auth-activation
1 parent 07a2fc6 commit c965a7a

46 files changed

Lines changed: 2863 additions & 290 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.

account/create-account.html

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta charset="utf-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1">
77
<title>Create Account - GameFoundryStudio</title>
8-
<meta name="description" content="Create a GameFoundryStudio account when account creation is available.">
8+
<meta name="description" content="Create a GameFoundryStudio account through configured DEV Supabase Auth.">
99
<link rel="icon" href="/favicon.svg">
1010
<link rel="stylesheet" href="../assets/theme-v2/css/theme.css">
1111
</head>
@@ -17,7 +17,7 @@
1717
<div class="container">
1818
<div class="kicker">Account</div>
1919
<h1>Create Account</h1>
20-
<p class="lede">Account creation will open when the production account flow is ready.</p>
20+
<p class="lede">Create an account through external DEV Supabase Auth when it is configured.</p>
2121
</div>
2222
</section>
2323
<section class="section">
@@ -26,11 +26,19 @@ <h1>Create Account</h1>
2626
<div class="card-body content-stack">
2727
<div>
2828
<div class="kicker">Account Access</div>
29-
<h2>Create Account Placeholder</h2>
29+
<h2>Create Account</h2>
3030
</div>
31-
<p>This page is reserved for the future account creation flow. No account data is collected here yet.</p>
31+
<p>Account creation is handled by external Supabase Auth when the DEV provider is configured.</p>
32+
<form class="content-stack" data-account-auth-form="create-account">
33+
<label for="createAccountEmail">Email</label>
34+
<input id="createAccountEmail" name="email" type="email" autocomplete="email" data-account-auth-email>
35+
<label for="createAccountPassword">Password</label>
36+
<input id="createAccountPassword" name="password" type="password" autocomplete="new-password" data-account-auth-password>
37+
<button class="btn primary" type="submit" data-account-auth-submit>Create Account</button>
38+
<div class="status" role="status" data-account-auth-status>Checking DEV Supabase Auth configuration.</div>
39+
</form>
3240
<div class="action-group">
33-
<a class="btn primary" href="sign-in.html">Back to Sign In</a>
41+
<a class="btn btn--compact" href="sign-in.html">Back to Sign In</a>
3442
</div>
3543
</div>
3644
</div>
@@ -39,6 +47,7 @@ <h2>Create Account Placeholder</h2>
3947
</main>
4048
<div data-partial="footer"></div>
4149
<script src="../assets/theme-v2/js/gamefoundry-partials.js" defer></script>
50+
<script type="module" src="../assets/theme-v2/js/account-auth-actions.js"></script>
4251
</body>
4352

4453
</html>

account/lost-password.html

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta charset="utf-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1">
77
<title>Lost Password - GameFoundryStudio</title>
8-
<meta name="description" content="Recover access to your GameFoundryStudio account.">
8+
<meta name="description" content="Use the current GameFoundryStudio password reset page.">
99
<link rel="icon" href="/favicon.svg">
1010
<link rel="stylesheet" href="../assets/theme-v2/css/theme.css">
1111
</head>
@@ -17,7 +17,7 @@
1717
<div class="container">
1818
<div class="kicker">Account</div>
1919
<h1>Lost Password</h1>
20-
<p class="lede">Recover access to your GameFoundryStudio account.</p>
20+
<p class="lede">Use the current password reset page for account recovery.</p>
2121
</div>
2222
</section>
2323
<section class="section">
@@ -26,11 +26,12 @@ <h1>Lost Password</h1>
2626
<div class="card-body content-stack">
2727
<div>
2828
<div class="kicker">Account Access</div>
29-
<h2>Password Reset</h2>
29+
<h2>Password Reset Moved</h2>
3030
</div>
31-
<p>Account features are being connected to the production authentication provider.</p>
31+
<p>Password reset now uses the dedicated account password reset page.</p>
3232
<div class="action-group">
33-
<a class="btn primary" href="sign-in.html">Back to Sign In</a>
33+
<a class="btn primary" href="password-reset.html">Open Password Reset</a>
34+
<a class="btn btn--compact" href="sign-in.html">Back to Sign In</a>
3435
</div>
3536
</div>
3637
</div>

account/password-reset.html

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta charset="utf-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1">
77
<title>Password Reset - GameFoundryStudio</title>
8-
<meta name="description" content="Reset a GameFoundryStudio account password when password reset is available.">
8+
<meta name="description" content="Request a GameFoundryStudio password reset through configured DEV Supabase Auth.">
99
<link rel="icon" href="/favicon.svg">
1010
<link rel="stylesheet" href="../assets/theme-v2/css/theme.css">
1111
</head>
@@ -17,7 +17,7 @@
1717
<div class="container">
1818
<div class="kicker">Account</div>
1919
<h1>Password Reset</h1>
20-
<p class="lede">Password reset will open when the production account flow is ready.</p>
20+
<p class="lede">Request a password reset through external DEV Supabase Auth when it is configured.</p>
2121
</div>
2222
</section>
2323
<section class="section">
@@ -26,11 +26,17 @@ <h1>Password Reset</h1>
2626
<div class="card-body content-stack">
2727
<div>
2828
<div class="kicker">Account Access</div>
29-
<h2>Password Reset Placeholder</h2>
29+
<h2>Password Reset</h2>
3030
</div>
31-
<p>This page is reserved for the future password reset flow. No account data is collected here yet.</p>
31+
<p>Password reset email delivery is handled by external Supabase Auth when the DEV provider is configured.</p>
32+
<form class="content-stack" data-account-auth-form="password-reset">
33+
<label for="passwordResetEmail">Email</label>
34+
<input id="passwordResetEmail" name="email" type="email" autocomplete="email" data-account-auth-email>
35+
<button class="btn primary" type="submit" data-account-auth-submit>Request Password Reset</button>
36+
<div class="status" role="status" data-account-auth-status>Checking DEV Supabase Auth configuration.</div>
37+
</form>
3238
<div class="action-group">
33-
<a class="btn primary" href="sign-in.html">Back to Sign In</a>
39+
<a class="btn btn--compact" href="sign-in.html">Back to Sign In</a>
3440
</div>
3541
</div>
3642
</div>
@@ -39,6 +45,7 @@ <h2>Password Reset Placeholder</h2>
3945
</main>
4046
<div data-partial="footer"></div>
4147
<script src="../assets/theme-v2/js/gamefoundry-partials.js" defer></script>
48+
<script type="module" src="../assets/theme-v2/js/account-auth-actions.js"></script>
4249
</body>
4350

4451
</html>

account/sign-in.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ <h2>Welcome Back</h2>
3636
<div class="action-group">
3737
<button class="btn primary" type="submit" data-login-submit>Sign In</button>
3838
<a class="btn" href="create-account.html" data-login-create-account>Create Account</a>
39-
<a class="btn btn--compact" href="lost-password.html" data-login-lost-password>Lost Password</a>
39+
<a class="btn btn--compact" href="password-reset.html" data-login-lost-password>Password Reset</a>
4040
</div>
41-
<div class="status" role="status" data-login-status>Account features are being connected to the production authentication provider.</div>
41+
<div class="status" role="status" data-login-status>Checking DEV Supabase Auth configuration.</div>
4242
</form>
4343
<div class="action-group">
4444
<a class="btn btn--compact" href="toolbox/index.html" data-login-continue>Continue Browsing</a>
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
const form = document.querySelector("[data-account-auth-form]");
2+
const emailField = document.querySelector("[data-account-auth-email]");
3+
const passwordField = document.querySelector("[data-account-auth-password]");
4+
const statusField = document.querySelector("[data-account-auth-status]");
5+
const submitButton = document.querySelector("[data-account-auth-submit]");
6+
const action = form?.getAttribute("data-account-auth-form") || "";
7+
let supabaseStatus = null;
8+
9+
function setStatus(message) {
10+
if (statusField) {
11+
statusField.textContent = message;
12+
}
13+
}
14+
15+
function isStaticOnlyLocalEntrypoint() {
16+
return ["127.0.0.1", "localhost"].includes(window.location.hostname) &&
17+
window.location.port === "5500";
18+
}
19+
20+
function setFormEnabled(enabled) {
21+
if (submitButton) {
22+
submitButton.disabled = !enabled;
23+
}
24+
}
25+
26+
async function readJson(response, fallbackMessage) {
27+
let payload = null;
28+
try {
29+
payload = await response.json();
30+
} catch {
31+
payload = null;
32+
}
33+
if (!response.ok || payload?.ok === false) {
34+
throw new Error(payload?.error || fallbackMessage);
35+
}
36+
return payload?.data || {};
37+
}
38+
39+
async function requestSupabaseAuth(path, options = {}) {
40+
const response = await fetch(`/api/auth/dev/supabase/${path}`, {
41+
body: options.body ? JSON.stringify(options.body) : undefined,
42+
headers: options.body ? { "content-type": "application/json" } : undefined,
43+
method: options.method || "GET",
44+
});
45+
return readJson(response, "DEV Supabase Auth API is unavailable. Start the API-backed local server.");
46+
}
47+
48+
function unavailableMessage(status) {
49+
return status?.message || "DEV Supabase Auth is unavailable. Configure GAMEFOUNDRY_SUPABASE_URL and GAMEFOUNDRY_SUPABASE_ANON_KEY on the local server.";
50+
}
51+
52+
async function refreshSupabaseStatus() {
53+
if (isStaticOnlyLocalEntrypoint()) {
54+
supabaseStatus = {
55+
ready: false,
56+
message: "Start the DEV API server to use Supabase Auth. Guest browsing remains available.",
57+
};
58+
setFormEnabled(false);
59+
setStatus(supabaseStatus.message);
60+
return supabaseStatus;
61+
}
62+
try {
63+
supabaseStatus = await requestSupabaseAuth("status");
64+
setFormEnabled(Boolean(supabaseStatus.ready));
65+
setStatus(supabaseStatus.ready ? "DEV Supabase Auth is ready." : unavailableMessage(supabaseStatus));
66+
} catch (error) {
67+
supabaseStatus = {
68+
ready: false,
69+
message: error instanceof Error ? error.message : String(error || "DEV Supabase Auth status failed."),
70+
};
71+
setFormEnabled(false);
72+
setStatus(supabaseStatus.message);
73+
}
74+
return supabaseStatus;
75+
}
76+
77+
function actionEndpoint() {
78+
if (action === "create-account") {
79+
return "create-account";
80+
}
81+
if (action === "password-reset") {
82+
return "password-reset";
83+
}
84+
return "";
85+
}
86+
87+
form?.addEventListener("submit", (event) => {
88+
event.preventDefault();
89+
Promise.resolve(supabaseStatus || refreshSupabaseStatus())
90+
.then((status) => {
91+
if (!status?.ready) {
92+
setStatus(unavailableMessage(status));
93+
return null;
94+
}
95+
const endpoint = actionEndpoint();
96+
if (!endpoint) {
97+
throw new Error("Unknown account action.");
98+
}
99+
return requestSupabaseAuth(endpoint, {
100+
body: {
101+
email: emailField?.value || "",
102+
password: passwordField?.value || "",
103+
},
104+
method: "POST",
105+
});
106+
})
107+
.then((result) => {
108+
if (result) {
109+
setStatus(result.message || "Supabase Auth action completed.");
110+
}
111+
})
112+
.catch((error) => {
113+
setStatus(error instanceof Error ? error.message : String(error || "Supabase Auth action failed."));
114+
});
115+
});
116+
117+
refreshSupabaseStatus();

assets/theme-v2/js/gamefoundry-partials.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
"sign-in": "account/sign-in.html",
9090
"create-account": "account/create-account.html",
9191
"lost-password": "account/lost-password.html",
92+
"password-reset": "account/password-reset.html",
9293
contact: "company/contact.html",
9394
vision: "company/vision.html",
9495
mission: "company/mission.html",
@@ -517,7 +518,8 @@
517518
if ([
518519
"account/sign-in.html",
519520
"account/create-account.html",
520-
"account/lost-password.html"
521+
"account/lost-password.html",
522+
"account/password-reset.html"
521523
].includes(pagePath)) {
522524
return null;
523525
}

assets/theme-v2/js/login-session.js

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
const continueLink = document.querySelector("[data-login-continue]");
22
const form = document.querySelector("[data-login-form]");
3+
const identityField = document.querySelector("[data-login-identity]");
4+
const passwordField = document.querySelector("[data-login-password]");
35
const statusField = document.querySelector("[data-login-status]");
6+
let supabaseStatus = null;
47

58
function rootPrefix() {
69
const rootSegments = new Set([
@@ -41,11 +44,85 @@ function setStatus(message) {
4144
}
4245
}
4346

47+
function isStaticOnlyLocalEntrypoint() {
48+
return ["127.0.0.1", "localhost"].includes(window.location.hostname) &&
49+
window.location.port === "5500";
50+
}
51+
52+
async function readJson(response, fallbackMessage) {
53+
let payload = null;
54+
try {
55+
payload = await response.json();
56+
} catch {
57+
payload = null;
58+
}
59+
if (!response.ok || payload?.ok === false) {
60+
throw new Error(payload?.error || fallbackMessage);
61+
}
62+
return payload?.data || {};
63+
}
64+
65+
async function requestSupabaseAuth(path, options = {}) {
66+
const response = await fetch(`/api/auth/dev/supabase/${path}`, {
67+
body: options.body ? JSON.stringify(options.body) : undefined,
68+
headers: options.body ? { "content-type": "application/json" } : undefined,
69+
method: options.method || "GET",
70+
});
71+
return readJson(response, "DEV Supabase Auth API is unavailable. Start the API-backed local server.");
72+
}
73+
74+
function unavailableMessage(status) {
75+
return status?.message || "DEV Supabase Auth is unavailable. Configure GAMEFOUNDRY_SUPABASE_URL and GAMEFOUNDRY_SUPABASE_ANON_KEY on the local server.";
76+
}
77+
78+
async function refreshSupabaseStatus() {
79+
if (isStaticOnlyLocalEntrypoint()) {
80+
supabaseStatus = {
81+
ready: false,
82+
message: "Start the DEV API server to use Supabase Auth. Guest browsing remains available.",
83+
};
84+
setStatus(supabaseStatus.message);
85+
return supabaseStatus;
86+
}
87+
try {
88+
supabaseStatus = await requestSupabaseAuth("status");
89+
setStatus(supabaseStatus.ready ? "DEV Supabase Auth is ready for sign-in." : unavailableMessage(supabaseStatus));
90+
} catch (error) {
91+
supabaseStatus = {
92+
ready: false,
93+
message: error instanceof Error ? error.message : String(error || "DEV Supabase Auth status failed."),
94+
};
95+
setStatus(supabaseStatus.message);
96+
}
97+
return supabaseStatus;
98+
}
99+
44100
if (continueLink) {
45101
continueLink.href = currentReturnTo();
46102
}
47103

48104
form?.addEventListener("submit", (event) => {
49105
event.preventDefault();
50-
setStatus("Account features are being connected to the production authentication provider.");
106+
Promise.resolve(refreshSupabaseStatus())
107+
.then((status) => {
108+
if (!status?.ready) {
109+
setStatus(unavailableMessage(status));
110+
return null;
111+
}
112+
return requestSupabaseAuth("sign-in", {
113+
body: {
114+
identity: identityField?.value || "",
115+
password: passwordField?.value || "",
116+
},
117+
method: "POST",
118+
});
119+
})
120+
.then((result) => {
121+
if (result) {
122+
setStatus(result.message || "Supabase Auth sign-in completed.");
123+
}
124+
})
125+
.catch((error) => {
126+
setStatus(error instanceof Error ? error.message : String(error || "Supabase Auth sign-in failed."));
127+
});
51128
});

0 commit comments

Comments
 (0)